Basics
How to write an if statement
Let’s say we want to check if any event is relevant. To do this, we use the flag variable. Remember that in FunCtrue
is -1
and false
is 0
.
To check whether an event is relevant, use a flag variable. In FunC, true
is represented by -1
, and false
is 0
.
==
operator is unnecessary, as 0
already evaluates to false
, and any nonzero value is considered true
.
Reference: If statement
in docs
How to write a repeat loop
A repeat loop helps execute an action a fixed number of times. The example below demonstrates exponentiation:Repeat loop
in docs
How to write a while loop
A while loop is useful when the number of iterations is unknown. The following example processes acell
which can store up to four references to other cells:
While loop
in docsCell
in docsslice_refs_empty?()
in docsstore_ref()
in docsbegin_cell()
in docsend_cell()
in docsbegin_parse()
in docs
How to write a do until loop
Use ado-until
loop when the loop must execute at least once.
Until loop
in docs
How to determine if slice is empty
Before working with aslice
, checking whether it contains any data is essential to ensure proper processing. The slice_empty?()
method can be used for this purpose. However, it returns 0
(false
) if the slice contains at least one bit
of data or one ref
.
slice_empty?()
in docsstore_slice()
in docsstore_ref()
in docsbegin_cell()
in docsend_cell()
in docsbegin_parse()
in docs
How to determine if slice is empty (no bits, but may have refs)
If only the presence ofbits
matters and refs
in slice
can be ignored, use the slice_data_empty?()
.
slice_data_empty?()
in docsstore_slice()
in docsstore_ref()
in docsbegin_cell()
in docsend_cell()
in docsbegin_parse()
in docs
How to determine if slice is empty (no refs, but may have bits)
In case we are only interested inrefs
, we should check their presence using slice_refs_empty?()
.
If only refs
are of interest, their presence can be checked using the slice_refs_empty?()
.
slice_refs_empty?()
in docsstore_slice()
in docsstore_ref()
in docsbegin_cell()
in docsend_cell()
in docsbegin_parse()
in docs
How to determine if a cell is empty
To check whether acell
contains any data, it must first be converted into a slice
.
- If only
bits
matter, useslice_data_empty?()
. - If only
refs
matter, useslice_refs_empty?()
. - If the presence of any data (
bits
orrefs
) needs to be checked, useslice_empty?()
.
slice_empty?()
in docsbegin_cell()
in docsstore_uint()
in docsend_cell()
in docsbegin_parse()
in docs
How to determine if a dict is empty
Thedict_empty?()
checks whether a dictionary contains any data. This method is functionally equivalent to cell_null?()
, as a null
cell typically represents an empty dictionary.
dict_empty?()
in docsnew_dict()
in docs, creating an empty dictdict_set()
in docs, adding some elements in dictd
with function, so it is not empty
How to determine if a tuple is empty
When working withtuples
, checking for existing values before extracting them is crucial. Extracting a value from an empty tuple will result in an error: “not a tuple of valid size” - exit code 7
.
tlen
assembly function. You can find more details here and a see a list of assembler commands.
References:
How to determine if a lisp-style list is empty
We can use the cons function to add an element to determine if a lisp-style list is empty. For example, adding 100 to the list ensures it is not empty.How to determine a state of the contract is empty
Consider a smart contract with acounter
that tracks the number of transactions. This variable does not exist in the contract state during the first transaction because it is empty.
It is important to handle this scenario by checking if the state is empty and initializing the counter
accordingly.
How to build an internal message cell
When a smart contract needs to send an internal message, it must first construct the message as acell
. This includes specifying technical flags, the recipient’s address, and additional data.
- In this example, we use the literal
a
to obtain an address. More details on string literals can be found in the documentation. - You can find more details in the documentation. A direct link to the layout is also available.
begin_cell()
in docsstore_uint()
in docsstore_slice()
in docsstore_coins()
in docsend_cell()
in docssend_raw_message()
in docs
How to contain a body as a ref in an internal message cell
The message body can containint
, slices
, or cells
following flags and other technical data. If a cell
is used, a bit must be set to 1
before calling store_ref()
, indicating that the cell
will be included.
Alternatively, if there is sufficient space, the message body can be stored in the same cell
as the header. In this case, the bit should be set to 0
.
- In this example, we use the literal
a
to obtain an address. More details on string literals can be found in the documentation. - The example uses
mode 3
, which ensures the contract deducts the specified amount while covering the transaction fee from the contract balance and ignoring errors.mode 64
returns all received tokens, subtracting the commission.mode 128
transfers the entire balance.
- The message is constructed with the body added separately.
begin_cell()
in docsstore_uint()
in docsstore_slice()
in docsstore_coins()
in docsend_cell()
in docssend_raw_message()
in docs
How to contain a body as a slice in an internal message cell
A message body can be sent as either acell
or a slice
. In this example, the body is sent inside a slice
.
- The literal
a
is used to obtain an address. See the documentation for details on string literals. - The example uses
mode 3
,mode 64
, andmode 128
, as described above. - The message is constructed with the body included as a slice.
How to iterate tuples (both directions)
When working with arrays or stacks in FunC, tuples are essential. The first step is learning how to iterate through tuple values for processing.- The
tlen
assembly function is declared here. You can read more about it and explore a list of all assembler commands. - The
to_tuple
function is also declared. This function converts any input into a tuple, so use it carefully.
How to write custom functions using asm keyword
Many features we use in FunC come from pre-prepared methods insidestdlib.fc
. However, we have many more capabilities, and learning to write custom functions unlocks new possibilities.
For example, while tpush
, which adds an element to a tuple
, exists, there is no built-in tpop
function. In such cases, we must implement it ourselves.
tuple
. We can achieve this by writing a new function using the TLEN
asm instruction.
stdlib.fc
:
Iterating n-nested tuples
Sometimes, we need to iterate through nested tuples. The following example iterates through a tuple formatted as:[[2,6],[1,[3,[3,5]]], 3]
starting from the head.
Basic operations with tuples
Resolving type X
If a tuple contains various data types X (cell, slice, int, tuple, etc.), we may need to check the value and cast it accordingly before processing.TVM instructions
in docs
How to get current time
How to generate a random number
This method is not cryptographically secure.
For more details, see Random number generation section.
Modulo operations
As an example, let’s say we need to perform the following calculation for all 256 numbers:(xp + zp) * (xp - zp)
.
Since these operations are commonly used in cryptography, we utilize the modulo operator for montgomery curves.
Note:
Variable names like xp+zp
are valid as long as there are no spaces between the operators.
muldivmod
in docs
How to throw errors
Reversing tuples
Since tuples behave as stacks in FunC, sometimes we need to reverse them to access data from the opposite end.tpush()
in docs
How to remove an item with a certain index from the list
Determine if the slices are equal
There are two main ways to check if two slices are equal:- Comparing their hashes.
- Using the SDEQ asm instruction.
Determine if the cells are equal
We can determine if two cells are equal by comparing their hashes.cell_hash()
in docs
Determine if the tuples are equal
A more advanced approach involves iterating through tuples and comparing each value recursively. Since tuples can contain different data types, we must check and cast values dynamically.Generate an internal address
When deploying a new contract, we need to generate its internal address because it is initially unknown. Suppose we already havestate_init
, which contains the code and data of the new contract.
This function creates an internal address corresponding to the MsgAddressInt
TLB.
workchain()
to retrieve the WorkChain ID. You can learn more about the WorkChain ID in docs.
Reference: cell_hash()
in docs
Generate an external address
We use the TL-B scheme from block.tlb to determine the address format to generate an external address.UBITSIZE
opcode. This function will return the minimum number of bits required to store a given number.
Reference: TVM instructions in docs
How to store and load dictionary in a local storage
The logic for loading a dictionary from local storage is as follows:How to send a simple message
To send a simple message with a comment, prepend the message body with32 bits
set to 0
, indicating that it is a comment
.
Message layout
in docs
How to send a message with an incoming account
A proxy contract can facilitate secure message exchange if interaction between a user and the main contract is needed.How to send a message with the entire balance
To transfer the entire balance of a smart contract, use sendmode 128
. This is particularly useful for proxy contracts that receive payments and forward them to the main contract.
How to send a message with a long text comment
Acell
can store up to 127 characters (<1023 bits
).
A sequence of linked cells (“snake cells”) must be used if more space is required.
Internal messages
in docs
How to get only data bits from a slice (without refs)
Ifrefs
within a slice
are unnecessary, only the raw data bits can be extracted for further processing.
How to define a custom modifying method
Modifying methods allow data to be updated within the same variable, similar to references in other programming languages.Modifying methods
in docs
How to raise number to the power of n
How to convert string to int
How to convert int to string
How to iterate dictionaries
Dictionaries are useful for managing large datasets. The built-in methodsdict_get_min?
and dict_get_max
retrieve the minimum and maximum key values, while dict_get_next?
allows dictionary iteration.
Dictonaries primitives
in docsdict_get_max?()
in docsdict_get_min?()
in docsdict_get_next?()
in docsdict_set()
in docs
How to delete value from dictionaries
How to iterate a cell tree recursively
Eachcell
can store up to 1023 bits
of data and 4 refs
. A tree of cells can be used to handle more complex data structures, requiring recursive iteration.
How to iterate through lisp-style list
A tuple can hold up to 255 values. If more space is needed, a lisp-style list can be used by nesting tuples within tuples, effectively bypassing the limit.How to send a deploy message (with StateInit
only, with StateInit
and body)
How to build a StateInit
cell
How to calculate a contract address (using StateInit
)
How to update the smart contract logic
Below is an example of a simpleCounterV1
smart contract that allows the counter to be incremented and includes logic for updating the contract.
CounterV1
and add a new decrease
function next to the existing increase
function. Your updated code will look like this:
CounterV2
smart contract is ready, you need to compile it off-chain into a cell
and send an upgrade message to the CounterV1
contract: