Documentation Index
Fetch the complete documentation index at: https://companyname-a7d5b98e-onchain-lib-edits.mintlify.app/llms.txt
Use this file to discover all available pages before exploring further.
Imports
Imports must appear at the top of the file:
import "another-file"
// Symbols from `another-file.tolk` become available in this file.
In most workflows, the IDE adds imports automatically. For example, when selecting an item from auto-completion.
The entire file is imported. There are no modules or exports; all symbols must have unique names within the project.
Structures
A struct Point holding two 8-bit integers:
struct Point {
x: int8
y: int8
}
fun demo() {
// create an object
val p1: Point = { x: 10, y: 20 };
// the same, type of p2 is auto-inferred
val p2 = Point { x: 10, y: 20 };
}
- Methods are declared as
fun Point.method(self).
- Fields can use any types: numeric, cell, union, and others.
- Fields can define default values:
x: int8 = 0.
- Fields can be
private and readonly.
- Structs can be generic:
struct Wrapper<T> { ... }.
If all fields are serializable, a struct can be automatically serialized:
// makes a cell containing hex "0A14"
val c = p1.toCell();
// back to { x: 10, y: 20 }
val p3 = Point.fromCell(c);
Functions
A function that returns the sum of two integers:
fun sum(a: int, b: int): int {
return a + b;
}
- Parameter types are mandatory.
- The return type can be omitted: it is auto-inferred.
- Parameters can define default values:
fun f(b: int = 0)
- Statements in a block are separated by semicolons
;.
- Generic functions are supported:
fun f<T>(value: T) { ... }
- Assembler functions are supported:
fun f(...): int asm "..."
Methods
A function declared as fun <receiver>.name(...) is a method.
- If the first parameter is
self, it’s an instance method.
- If the first parameter is not
self, it’s a static method.
// `self` — instance method (invoked on a value)
fun Point.sumCoords(self) {
return sum(self.x, self.y);
}
// not `self` — static method
fun Point.createZero(): Point {
return { x: 0, y: 0 };
}
fun demo() {
val p = Point.createZero(); // { 0, 0 }
return p.sumCoords(); // 0
}
By default, self is immutable; mutate self allows modifying the object.
Methods can be declared for any type, including primitives:
fun int.isNegative(self) {
return self < 0
}
Variables
Within functions, variables are declared with val or var keywords. The val keyword declares an immutable variable that can be assigned only once:
val coeff = 5;
// cannot change its value, `coeff += 1` is an error
The var keyword declares a variable that can be reassigned:
var x = 5;
x += 1; // now 6
A variable’s type can be specified after its name:
Declaring variables at the top level, outside functions, is supported using the global keyword.
Constants
Constants can be declared only at the top level, not inside functions:
const ONE = 1
const MAX_AMOUNT = ton("0.05")
const ADMIN_ADDRESS = address("EQ...")
To group integer constants, enums are useful.
Value semantics
Tolk follows value semantics: assignments create independent copies, and function calls do not mutate arguments unless explicitly specified.
var a = Point { x: 1, y: 2 };
var b = a; // `b` is a copy
b.x = 99; // `a.x` remains 1
someFn(a); // pass a copy; `a` will not change
// but there can be mutating functions, called this way:
anotherFn(mutate a);
Semicolons
- Semicolons are optional at the top level, after imports, aliases, etc.
- Semicolons are required between statements in a function.
- After the last statement in a block, a semicolon is optional.
// optional at the top-level
const ONE = 1
type UserId = int
// required inside functions
fun demo() {
val x = 5;
val y = 6;
return x + y // optional after the last statement
}
Tolk supports single-line or end-of-line and multi-line or block comments:
// This is a single-line comment
/* This is a block comment
across multiple lines. */
const TWO = 1 /* + 100 */ + 1 // 2
Conditional operators
In conditions, if is a statement. else if and else blocks are optional.
fun sortNumbers(a: int, b: int) {
if (a > b) {
return (b, a)
} else {
return (a, b)
}
}
A ternary operator is also available:
val sign = a > 0 ? 1 : a < 0 ? -1 : 0;
Union types and matching
Union types allow a variable to hold one of possible types. They are typically handled by match:
fun processValue(value: int | slice) {
match (value) {
int => {
value * 2
}
slice => {
value.loadUint(8)
}
}
}
Alternatively, test a union with is or !is operators:
fun processValue(value: int | slice) {
if (value is slice) {
// call methods for `slice`
return;
}
// value is `int`
return value * 2;
}
Union types are commonly used when handling incoming messages.
While loop
Tolk does not have a for loop; use while loop for repeated execution.
while (i > 0) {
// ...
i -= 1;
}
Assert and throw
The try-catch statement is supported for exceptions, although it is not commonly used in contracts.
const ERROR_NO_BALANCE = 403;
// in some function
throw ERROR_NO_BALANCE;
// or conditional throw
assert (balance > 0) throw ERROR_NO_BALANCE;
Arrays
Arrays are dynamically sized containers created with [...]:
var numbers = [1, 2, 3]; // array<int>
numbers.push(4);
numbers.get(0); // 1
Iterate over a map
To iterate, maps can be used:
fun iterateOverMap(m: map<int32, Point>) {
var r = m.findFirst();
while (r.isFound) {
// ...
r = m.iterateNext(r);
}
}
Send a message to another contract
To construct and send a message, a message body is typically represented by a structure. For example, RequestedInfo:
val reply = createMessage({
bounce: BounceMode.NoBounce,
value: ton("0.05"),
dest: someAddress,
body: RequestedInfo { ... }
});
reply.send(SEND_MODE_REGULAR);
Contract getters
Contract getters or get-methods are declared with get fun:
get fun currentOwner() {
val storage = lazy Storage.load();
return storage.ownerAddress;
}