This section covers the stdlib.fc library, which provides standard functions for FunC.
Tuple manipulation primitives
Most function names and types in this section are self-explanatory. For more details on polymorphic functions, refer to the Polymorphism with forall section. Note: Currently, values of atomic typetuple
cannot be converted into composite tuple types (e.g.,[int, cell]
) and vice versa.
Lisp-style lists
Lists can be represented as nested 2-element tuples. Empty list is conventionally represented as TVMnull
value (it can be obtained by calling null()
). For example, the tuple (1, (2, (3, null)))
represents the list [1, 2, 3]
. Elements of a list can be of different types.
Lists in FunC are represented as nested two-element tuples. An empty list is conventionally represented by the TVM null
value, which can be obtained using null()
.
For example, the tuple (1, (2, (3, null)))
corresponds to the list [1, 2, 3]
. Lists in FunC can contain elements of different types.
cons
uncons
list_next
car
cdr
Other tuple primitives
empty_tuple
tpush
(x1, ..., xn)
, forming (x1, ..., xn, x)
. The resulting tuple must not exceed 255 elements,
or a type check exception is thrown.
single
unsingle
pair
unpair
triple
untriple
tuple4
untuple4
Tuple element access
first
second
third
fourth
Pair and triple element access
pair_first
pair_second
triple_first
triple_second
triple_third
Domain specific primitives
Extracting info from c7
The c7 special register holds useful data about smart contract execution. The following primitives facilitate easy retrieval of this information:now
my_address
MsgAddressInt
. If needed, it can be further processed using functions like parse_std_addr
.
get_balance
tuple
:
int
: The remaining balance in nanotoncoins.cell
: A dictionary (with 32-bit keys) containing balances of extra currencies.
value
, with storage_fee
and import_fee
already subtracted.
Raw primitives such as
send_raw_message
do not update this field.cur_lt
block_lt
config_param
i
as cell
or null
value.
my_code
c7
.
This function is not included in the standard library, but is often sought by developers. You need to manually add initialization it to your contract system, with the
asm
word specified as shown in the snippet above.Hashes
cell_hash
cell c
and returns it as a 256-bit unsigned integer x
.
This function is handy for signing and verifying signatures of arbitrary entities structured as a tree of cells.
slice_hash
slice s
and returns it as a 256-bit unsigned integer x
.
The result is equivalent to creating a standard cell containing only the data and references
from s
and then computing its hash using cell_hash
.
string_hash
slice s
.
A cell underflow exception is thrown if the bit length of s
is not a multiple of eight.
The hash is returned as a 256-bit unsigned integer x
.
Signature checks
check_signature
signature
is a valid Ed25519 signature of the provided
hash
using the specified public key
. The hash
and public key
are both 256-bit unsigned integers. The signature
must be at least 512 bits long, and only the first 512 bits are used.
If the signature is valid, the function returns -1
; otherwise, it returns 0
.
Remember that CHKSIGNU
converts the hash into a 256-bit slice and then calls CHKSIGNS
.
This means that if the hash
was initially generated from some data,
that data gets hashed twice — the first time when creating the hash and the second time within CHKSIGNS
.
check_data_signature
signature
is a valid Ed25519 signature for the data contained in the slice data
,
using the specified public key
, just like check_signature
.
A cell underflow exception is thrown if the data bit length is not a multiple of eight.
The verification follows the standard Ed25519 process,
where SHA-256 is used to derive a 256-bit number from data
, which is then signed.
Computation of BoC size
The following functions help calculate storage fees for user-provided data.compute_data_size?
(x, y, z, -1)
or (null, null, null, 0)
. It recursively calculates the number of unique cells x
, data bits y
, and cell references z
in the directed acyclic graph (DAG) at cell c
. This provides the total storage used by the DAG while recognizing identical cells.
The computation uses a depth-first traversal with a hash table to track visited cells, preventing redundant visits.
If the total amount of visited cells x
exceeds max_cells
, the process stops before visiting the (max_cells + 1)
-th cell, and the function returns 0
to indicate failure. If c
is null
, the function returns x = y = z = 0
.
slice_compute_data_size?
compute_data_size?
but takes a slice s
instead of a cell
. The result x
does not include the cell that contains the slice s
, but y
and z
account for the data bits and cell references inside s
.
compute_data_size
compute_data_size?
that throws a cell overflow exception (8) if the computation fails.
slice_compute_data_size
slice_compute_data_size?
that throws a cell overflow exception (8) if the computation fails.
Persistent storage save and load
get_data
set_data
c
as persistent contract data. You can update the persistent contract storage with this primitive.
Continuation primitives
get_c3
c3
register typically holds a continuation set up by the contract code.
It is used for function calls.
The primitive returns the current value of c3
.
set_c3
c3
value to modify the contract’s execution code at runtime. The current code and function call stack remain unchanged, but future function calls use the updated code.
bless
slice s
into a basic continuation c
, where c.code = s
, an empty stack and a savelist.
Gas related primitives
accept_message
gl
to its maximum possible value gm
and resets the gas credit gc
to zero.
At the same time, it deducts the previous gas credit gc
from the remaining gas reserve gr
.
Simply put, the smart contract agrees to purchase gas to complete the transaction.
This function is required when processing external messages that do not carry any value and do not provide gas.
For more details,
follow the Accept message effects section.
set_gas_limit
gl
to the smaller of two values: the provided limit
or the maximum allowed gas gm
.
It also resets the gas credit gc
to zero. If the contract already uses more gas than this new limit gl
, including the current instruction, an out-of-gas exception is triggered before the new limit is applied.
Remember that if the limit
is 2^63 − 1
or higher, calling set_gas_limit
works the same as calling accept_message
.
For more details,
follow the Accept message effects section.
commit
c4
and action registers c5
, ensuring execution succeeds with these stored values,
even if an exception occurs later.
buy_gas
The
BUYGAS
opcode is currently not implemented.gram
nanotoncoins and updates the gas limit gl
accordingly,
similar to set_gas_limit
.
Actions primitives
raw_reserve
raw_reserve
function creates an output action
that reserves a specific amount of nanotoncoins from the account’s remaining balance.
The behavior depends on the mode
parameter:
- If
mode = 0
, exactly theamount
of nanotoncoins is reserved. - If
mode = 2
, up to theamount
of nanotoncoins is reserved. - If
mode = 1
ormode = 3
, all but theamount
of nanotoncoins is reserved.
amount
of nanotoncoins or b − amount
nanotoncoins,
where b
represents the remaining balance, to the sender. This ensures that subsequent output actions cannot exceed the remaining funds.
Mode Flags
- Bit +2 in
mode
: prevents failure if the specifiedamount
cannot be reserved. Instead, the entire remaining balance is reserved. - Bit +8 in
mode
: negatesamount
(amount <- -amount
) before executing further actions. - Bit +4 in
mode
: increasesamount
by the original balance of the current account before the compute phase, including all extra currencies, before performing any other checks and actions.
- The
amount
must be a non-negative integer. mode
must be within the range0..15
.
raw_reserve_extra
raw_reserve
, but it also supports an extra_amount
dictionary.
This dictionary, given as a cell
or null
, allows reserving currencies other than Toncoin.
send_raw_message
msg
. This message must contain a properly serialized Message X
object, with a few exceptions.
The source address can have a dummy value addr_none
, which the current smart contract address will automatically replace. The fields ihr_fee
, fwd_fee
, created_lt
, and created_at
can hold arbitrary values, as they will be updated with the correct ones during the action phase of the transaction. The integer parameter mode
specifies the flags.
Currently, there are 3 modes and 4 flags available for messages.
A single mode can be combined with multiple flags or none to form the desired mode
.
The combination is achieved by summing their values. The table below provides descriptions of the available modes and flags.
Mode | Description |
---|---|
0 | Sends an ordinary message. |
64 | Transfers the full remaining value of the inbound message and the initially specified amount. |
128 | Transfers the entire remaining balance of the current smart contract instead of the initially specified amount. |
Flag | Description |
---|---|
+1 | Pays transfer fees separately from the message value. |
+2 | Ignores certain errors that occur while processing the message during the action phase (see note below). |
+16 | Bounces the transaction if the action fails. Has no effect if +2 is used. |
+32 | Destroys the current account if its resulting balance is zero (commonly used with mode = 128 ). |
+2 flagThe
+2
flag ignores specific errors that may occur while processing a message during the action phase. These include:- Insufficient Toncoins:
- Not enough value to transfer with the message (the entire inbound message value has been used).
- Insufficient funds to process the message.
- Not enough attached value to cover forwarding fees.
- Insufficient extra currency to send with the message.
- Not enough funds to pay for an outbound external message.
- Message exceeds size limits (see the Message size section for details).
- Excessive Merkle depth in the message.
+2
flag does not ignore errors in the following cases:- The message format is invalid.
- Both
64
and128
modes are used simultaneously. - The outbound message contains invalid libraries in
StateInit
. - The external message is not ordinary or includes the
+16
or+32
flag.
- +16 flag should not be used in external messages (e.g., to wallets), as there is no sender to receive the bounced message.
- +2 flag is important in external messages (e.g., to wallets).
set_code
new_code
cell.
This change occurs only after the smart contract completes its current execution.
See also set_c3.
Random number generator primitives
The pseudo-random number generator relies on a random seed, a 256-bit unsigned integer, and sometimes additional data stored in c7. Before a smart contract executes in the TON Blockchain, its initial random seed is derived from a hash of the smart contract address and the global block random seed. If the same smart contract runs multiple times within a block, each run will use the same random seed. This can be adjusted by callingrandomize_ltbefore
using the pseudo-random number generator for the first time.
Remember that the random numbers generated by the functions below can be predicted unless additional techniques are used. See random number generation for more info.
random
x
. The process works as follows:
- Let
r
be the previous random seed, a 32-byte array constructed from the big-endian representation of a 256-bit unsigned integer. - Compute
sha512(r)
. - The first 32 bytes of the hash become the new seed
r'
. - The remaining 32 bytes are returned as the new random value
x
.
rand
z
in the range 0..range−1
(or range..−1
if range < 0
). More precisely, an unsigned random value x
is generated as in random
; then z := x * range / 2^256
is
computed.
Produces a pseudo-random integer z
within the range 0..range−1
(or range..−1
if range < 0
).
- First, an unsigned random value
x
is generated usingrandom()
. - Then,
z := x * range / 2^256
is calculated.
get_seed
set_seed
seed
.
randomize
x
into a random seed r
by setting the random seed to sha256 of the concatenation of two 32-byte strings: the first with a big-endian representation of the old seed r
, and the second with a big-endian representation of x
.
Mixes a 256-bit unsigned integer x
into the random seed r
by updatingr
to sha256(r || x)
, where:
r
is the previous seed, represented as a 32-byte big-endian array.x
is also converted into a 32-byte big-endian array. T- he new seed is the SHA-256 hash of their concatenation.
randomize_lt
randomize(cur_lt());
.
Address manipulation primitives
The functions below handle the serialization and deserialization of values based on the following TL-B scheme.addr_none
is represented byt = (0)
, i.e., a tuple containing exactly one integer that equals zeroaddr_extern
is represented byt = (1, s)
, where slices
contains the fieldexternal_address
. In other words,t
is a pair (a tuple consisting of two entries), containing an integer equal to one and slices
addr_std
is represented byt = (2, u, x, s)
, whereu
is eithernull
(ifanycast
is absent) or a slices'
containingrewrite_pfx
(ifanycast
is present). Next, integerx
is theworkchain_id
, and slices
contains the addressaddr_var
is represented byt = (3, u, x, s)
, whereu
,x
, ands
have the same meaning as foraddr_std
MsgAddress
cis represented as a tuple t
with the following structure:
addr_none
is represented ast = (0)
, a single-element tuple where the integer is zero.addr_extern
is represented ast = (1, s)
, wheres
is a slice containingexternal_address
. In other words,t
is a pair with the first element being1
and the second beings
.addr_std
is represented ast = (2, u, x, s)
, where:u
isnull
ifanycast
is absent or a slices'
containingrewrite_pfx
ifanycast
is present.x
is theworkchain_id
.s
is a slice containing the address.
addr_var
is represented ast = (3, u, x, s)
, whereu
,x,
ands
follow the same structure asaddr_std
.
load_msg_addr
MsgAddress
prefix from slice s
and returns the extracted prefix s'
and the remaining part s''
.
parse_addr
slice s
, which holds a valid MsgAddress
, into tuple t
, separating its fields. If s
is invalid, a cell deserialization exception is raised.
parse_std_addr
MsgAddressInt
, typically msg_addr_std
, from slice s
, modifies the address prefix if anycast
is present, and returns the workchain and 256-bit address as integers. A cell deserialization
exception is triggered if the address isn’t 256-bit
or s
isn’t a valid MsgAddressInt
serialization.
parse_var_addr
parse_std_addr
that returns the modified address as slice s
,
even if its length is not exactly 256 bits, as in msg_addr_var
.
Debug primitives
Debug primitives help inspect the state of various variables while running tests or executing console scripts.~dump
~dump([v1, v2, v3])
.
~strdump
dump_stack
Slice primitives
A primitive loads data when it returns both the extracted data and the remainder of the slice. It can be used as a modifying method. A primitive preloads data when it returns only the extracted data, leaving the original slice unchanged. It can be used as a non-modifying method. Unless specified otherwise, loading and preloading primitives read data from the beginning of the slice.begin_parse
cell
into a slice
. The input c
must be either an ordinary or exotic cell.
See TVM.pdf, 3.1.2. If c
is exotic, it is automatically converted into an ordinary cell c'
before being transformed into a slice
.
end_parse
slice s
is empty. It throws an exception if it is not.
load_ref
preload_ref
load_int
len
-bit integer from a slice.
load_uint
len
-bit integer from a slice.
preload_int
len
-bit integer from a slice.
preload_uint
len
-bit integer from a slice.
load_bits
0 ≤ len ≤ 1023
bits from slice s
into a new slice s''
.
preload_bits
0 ≤ len ≤ 1023
bits from slice s
into a new slice s''
.
load_coins
2^120 - 1
.
skip_bits
s
except for the first len
bits, where 0 ≤ len ≤ 1023
.
first_bits
len
bits of s
, where 0 ≤ len ≤ 1023
.
skip_last_bits
s
except for the last len
bits, where 0 ≤ len ≤ 1023
.
slice_last
len
bits of s
, where 0 ≤ len ≤ 1023
.
load_dict
D
from slice s
. It can be used for dictionaries or to values of arbitrary Maybe ^Y
types (returns null
if the nothing
constructor is used).
preload_dict
D
from slice s
.
skip_dict
load_dict
but returns only the remainder of the slice.
Slice size primitives
slice_refs
s
.
slice_bits
s
.
slice_bits_refs
s
.
slice_empty?
s
is empty (i.e., contains no bits of data and no cell references).
slice_data_empty?
s
has no bits of data.
slice_refs_empty?
s
has no references.
slice_depth
s
.
If s
has no references, it returns 0
;
otherwise, the returned value is one plus the maximum depths of cells referred to from s
.
Builder primitives
A primitive stores a valuex
in a builder b
by returning a modified version b'
with x
added at the end. It can also be used as a non-modifying method.
Each of the following primitives first checks for enough space in the builder
and then verifies the range of the serialized value.
begin_cell
builder
.
end_cell
builder
into a standard cell
.
store_ref
c
in builder b
.
store_uint
len
-bit integer x
in b
, where 0 ≤ len ≤ 256
.
store_int
len
-bit integer x
in b
, where 0 ≤ len ≤ 257
.
store_slice
s
in builder b
.
store_grams
store_coins
x
in the range 0..2^120 − 1
into builder b
. The serialization consists of:
- A 4-bit unsigned big-endian integer
l
, the smallestl ≥ 0
such thatx < 2^8l
. - An
8l
-bit unsigned big-endian representation ofx
.
x
is outside the supported range.
This is the standard way of storing Toncoins.
store_dict
D
represented by cell c
or null
into builder b
. Stores a 1-bit and a reference to c
if c
is not null
; otherwise, stores a 0-bit.
store_maybe_ref
store_dict
.
Builder size primitives
builder_refs
b
.
builder_bits
b
.
builder_depth
b
. If b
contains no cell references, it returns 0
. Otherwise, it returns 1
plus the maximum depth among the referenced cells.
Cell primitives
cell_depth
cell c
. If c
has no references, the function returns 0
. Otherwise, it returns 1
plus the maximum depth among all cells referenced by c
. If c
is null
instead of a cell, the function returns 0
.
cell_null?
cell c
is null
. In most cases, a null
cell represents an empty dictionary. FunC also includes a polymorphic null?
built-in function. See built-in for more details.
Dictionaries primitives
The dictionary primitives below are low-level and do not verify whether the cell structure matches the expected operation.
Using a dictionary operation on a “non-dictionary” cell results in undefined behavior. The same applies when using keys of different lengths or types, such as writing to a dictionary using an 8-bit signed key and a 7-bit unsigned key.In most cases, this will cause an exception. However, in rare cases, it may lead to incorrect values being written or read. Developers should avoid such code.
Dictionaries can be represented in two different ways as TVM stack values:In FunC, dictionaries are also represented asMost dictionary-related operations use the second format because it is easier to manipulate on the stack. However, when dictionaries are serialized within larger TL-B objects, they follow the first representation.
- As a slice
s
containing the serialized TL-B value of typeHashmapE(n, X)
. In simpler terms,s
consists either of a single0
bit if the dictionary is empty or a1
bit followed by a reference to a cell containing the binary tree’s root — essentially, a serialized value of typeHashmap(n, X)
.- As a
Maybe cell (c^?)
, which is either a cell that contains a serializedHashmap(n, X)
same as above ornull
, indicating an empty dictionary. See null values for details. When using this format, the dictionary is typically referred to asD
.
cells
with the implicit assumption that they can be null
. There are no separate types for dictionaries with different key lengths or value types — after all, this is FunC, not FunC++.
Taxonomy note
A dictionary primitive interprets dictionary keys in one of three ways:- Unsigned
l
-bit integers (denoted by u); - Signed
l
-bit integers (denoted by i); l
-bit slices (no prefix).
udict_set
is a set-by-key function for dictionaries with unsigned integer keys.idict_set
is the equivalent function for signed integer keys.dict_set
applies to dictionaries with slice keys.
~
, enabling them to be used as modifying methods.
Dictionary values
Values in a dictionary can be stored in two ways:- As a subslice within an inner dictionary cell.
- As a reference to a separate cell.
dict_set
dict
by setting the value corresponding to the key_len
-bit key index
to value
, a slice, and returns the updated dictionary.
dict_set_ref
dict_set
, but it sets the value to a reference of cell value
.
dict_get?
index
in the dict
dictionary with key_len
-bit keys. It retrieves the associated value as a slice
and returns a success flag of -1
if found. If not found, it returns (null, 0)
.
dict_get_ref?
dict_get?
, but it returns the first reference of the found value.
dict_get_ref
dict_get_ref?
returns null
if the key index
is absent in the dictionary dict
.
dict_set_get_ref
index
to value
. If the value
is null
, the key is deleted.
It then returns the old value or null
if it wasn’t present.
dict_delete?
key_len
-bit key index
from the dictionary dict
. It returns the modified dictionary and a success flag of -1
if successful.
If the key is not found, it returns the original dictionary and 0
.
dict_delete_get?
key_len
-bit key index
from the dictionary dict
. If the key is found, it returns the modified dictionary, the original value associated with the key as a Slice, and the success flag -1
. If the key is not found, it returns (dict, null, 0)
.
dict_add?
add
operation is similar to dict_set
but only sets the value if the key index
does not already exist in the dictionary dict
. It returns the modified dictionary and a success flag of -1
or (dict, 0)
.
dict_replace?
replace
operation works like dict_set
, but it only updates the value for the index
if the key is already present in the dictionary dict
. It returns the modified dictionary and a success flag of -1
or (dict, 0)
.
Builder counterparts
The following primitives accept a builder as the new value instead of a slice, making them more convenient when the value needs to be serialized from multiple components computed on the stack. Functionally, this is equivalent to converting the builder into a slice and executing the corresponding primitive listed above.dict_set_builder
dict_set
but takes a builder as input.
dict_add_builder?
dict_add?
, but uses a builder.
dict_replace_builder?
dict_replace?
, but uses a builder.
dict_delete_get_min
k
in the dictionary dict
, removes it, and returns (dict', k, x, -1)
, where dict'
is the updated dictionary and x
is the value associated with k
. If the dictionary is empty, it returns (dict, null, null, 0)
.
Note: The key returned by idict_delete_get_min
may differ from that returned by dict_delete_get_min
and udict_delete_get_min
.
dict_delete_get_max
k
in the dictionary dict
, removes it, and returns (dict', k, x, -1)
, where dict'
is the updated dictionary and x
is the value associated with k
. If the dictionary is empty, it returns (dict, null, null, 0)
.
dict_get_min?
k
in the dictionary dict
and returns (k, x, -1)
, where x
is the value associated with k
. If the dictionary is empty, it returns (null, null, 0)
.
dict_get_max?
k
in the dictionary dict
and returns (k, x, -1)
, where x
is the value associated with k
. If the dictionary is empty, it returns (null, null, 0)
.
dict_get_min_ref?
dict_get_min?
but it returns a reference.
dict_get_max_ref?
dict_get_max?
but it returns a reference.
dict_get_next?
k
in dict
that is greater than the pivot
. Returns k
, associated value, and a success flag. If the dictionary is empty, it returns (null, null, 0)
.
dict_get_nexteq?
dict_get_next?
, but instead finds the smallest key k
that is greater than or equal to the pivot
.
dict_get_prev?
dict_get_next?
, but instead finds the largest key k
that is less than the pivot
.
dict_get_preveq?
dict_get_prev?
, but instead finds the largest key k
that is less than or equal to the pivot
.
new_dict
null
value — a special case of null()
.
dict_empty?
cell_null?
.
Prefix dictionaries primitives
TVM supports dictionaries with non-fixed length keys that follow a prefix code structure, meaning no key is a prefix of another key. Learn more in the TVM instruction section.pfxdict_get?
key
in the prefix code dictionary dict
. If found, returns (s', x, s'', -1)
, where:
s'
is the matching prefix ofs
,x
is the corresponding value (a slice),s''
is the remaining part ofs
,-1
indicates success.
(null, null, s, 0)
, where s
remains unchanged and 0
indicates failure.
pfxdict_set?
dict_set
but fails if the given key is a prefix of an existing key in dict. Returns a flag indicating success.
pfxdict_delete?
dict_delete?
.
Special primitives
null
Null
type in FunC represents the absence of a value for any atomic type, meaning null
can take on any atomic type.
~impure_touch
Other primitives
min
x
and y
.
max
x
and y
.
minmax
(min(x, y), max(x, y))
, sorting two integers.
abs
x
.