Generic selectors
Exact matches only
Search in title
Search in content
Post Type Selectors
/

Getting Started with Fift
Picture Getting Started with Fift: A Beginner’s Guide 2 | TON app

Getting Started with Fift

Learn the basics of Fift with our beginner’s guide. Explore essential tools, commands, and steps to get started in this powerful programming environment.
Picture Getting Started with Fift: A Beginner’s Guide 3 | TON app
Although using the Fift language isn’t a requirement for programming TON smart contracts, this guide is here to introduce you to Fift if you’d like to learn more about it.

Understanding Fift

Fift is a general-purpose, stack-based programming language specifically crafted for interaction with the TON Virtual Machine and the TON Blockchain.

What Does It Mean to Be Stack-Based?

In stack-oriented programming, data is handled using a stack machine model, a paradigm where the language operates with one or more stacks that serve specific functions. Fift, like other stack-based languages, often employs postfix or reverse Polish notation. This means that command arguments or parameters are placed before the command itself. For example, instead of writing multiply(2, 3) as you would in traditional notation, you would write 2 3 multiply in postfix notation.

Installation

To get started with Fift, you’ll need to obtain the Fift compiler binaries. You can either compile them from the source code or download the precompiled binaries from TON Autobuilds, depending on your platform.
Once installed, you should be able to run the Fift interpreter by simply typing fift in your terminal. If you encounter an error message like the one below:

  • “Check that the correct include path is set by -I or by the FIFTPATH environment variable, or disable the standard preamble by using -n.”
  • To resolve this, you can either set the FIFTPATH environment variable to point to the Fift libraries directory, or specify the directory path using the -I flag when running the interpreter.

Stack Notation

As previously mentioned, Fift utilizes postfix or reverse Polish notation. The Fift parser processes code sequentially, line by line. When it encounters a value, it pushes that value onto the stack; when it comes across a word, it executes it. In Fift, “words” can be thought of as function or code definitions, with both primitives and functions implemented as such. All words are stored in Fift’s global dictionary.
Primitives are predefined words within the interpreter’s implementation, while other words are defined in the Fift.fif standard library. Users can also define their own words and expand the dictionary as needed.
Each time the interpreter completes processing a line of code, it outputs “ok” to indicate successful execution.
Consider the following code snippet:

  • 2 3 + .

Here’s how it works: First, the number 2 is pushed onto the stack, followed by the number 3. The + primitive is then executed, which pops these two values from the stack, adds them together, and pushes the result back onto the stack. Finally, the . primitive is used to print the top value of the stack to the standard output. After running this code, the output will be:

  • 5 ok

To better understand the effect of each word in Fift, a notation is used that describes the state of the stack before and after the execution of a word. This notation follows the format word-name (before — after).
For further details, including documentation on primitives and standard library words, you can refer to the Fift Documentation, which provides notations and explanations of each function.

List of Useful Words in Fift

Below is a table of some predefined words in Fift, along with their notations and descriptions:

  • +
    Notation: (x y — x + y)
    Description: Replaces two integers, x and y, at the top of the stack with their sum, x + y.

  • Notation: (x y — x – y)
    Description: Computes the difference, x – y, between two integers x and y.
  • *
    Notation: (x y — xy)
    Description: Computes the product, xy, of two integers x and y.
  • /
    Notation: (x y — q := floor(x/y))
    Description: Computes the floor-rounded quotient of two integers, x and y.
  • <
    Notation: (x y — ?)
    Description: Checks whether x < y and pushes -1 if true, or 0 otherwise.
  • >, =, <>, <=, >=
    Notation: (x y — ?)
    Description: Compares x and y, pushing -1 or 0 based on the comparison result.
  • “<string>”
    Notation: ( — S)
    Description: Pushes a string literal onto the stack.
  • .”<string>”
    Notation: ( — )
    Description: Prints a constant string to the standard output.
  • type
    Notation: (S — )
    Description: Prints a string S taken from the top of the stack to the standard output.
  • cr
    Notation: ( — )
    Description: Outputs a carriage return (newline) to the standard output.
  • b{<binary-data>}
    Notation: ( – s)
    Description: Creates a slice s containing up to 1023 data bits, specified in <binary-data>, which is a string of ‘0’ and ‘1’ characters.
  • x{<hex-data>}
    Notation: ( – s)
    Description: Creates a slice s containing up to 1023 data bits, specified in <hex-data>.
  • <b
    Notation: ( – b)
    Description: Creates a new, empty builder b.
  • b>
    Notation: (b – c)
    Description: Converts a builder b into a new cell c containing the same data as b.
  • i,
    Notation: (b x y – b’)
    Description: Appends the binary representation of a signed y-bit integer x (where 0 <= y <= 257) to builder b.
  • u,
    Notation: (b x y – b’)
    Description: Appends the binary representation of an unsigned y-bit integer x (where 0 <= y <= 256) to builder b.
  • ref,
    Notation: (b c – b’)
    Description: Appends a reference to cell c to builder b.
  • s,
    Notation: (b s – b’)
    Description: Appends data bits and references from slice s to builder b.
  • $,
    Notation: (b S – b’)
    Description: Appends string S to builder b.
  • B>boc
    Notation: (B – c)
    Description: Deserializes a “standard” bag of cells represented by bytes B, returning the root cell c.
  • boc+>B
    Notation: (c x – B)
    Description: Creates and serializes a “standard” bag of cells with root cell c and all its descendants, where x represents flags for additional options.
  • B{<hex-digits>}
    Notation: ( – B)
    Description: Pushes a bytes literal containing data represented by an even number of hexadecimal digits.
  • Bx.
    Notation: (B – )
    Description: Prints the hexadecimal representation of a bytes value.
  • file>B
    Notation: (S – B)
    Description: Reads a binary file named in string S and returns its contents as a bytes value.
  • B>file
    Notation: (B S – )
    Description: Creates a new binary file named in string S and writes data from bytes B into the file.
  • smca>$
    Notation: (x y z – S)
    Description: Packs a standard TON smart contract address with workchain x (a signed 32-bit integer) and in-workchain address y (an unsigned 256-bit integer) into a 48-character string S, using flags z (where +1 indicates non-bounceable addresses, +2 for testnet-only addresses, and +4 for base64url instead of base64).
  • $>smca
    Notation: (S – x y z -1 or 0)
    Description: Unpacks a standard TON smart contract address from its human-readable string representation S.

Generating Messages with Fift

When interacting with smart contracts on the TON Network, it is often necessary to create and send messages to these contracts. While there are multiple methods to accomplish this, Fift is the primary and most recommended tool for crafting these messages.
Constructing an Internal Message with Fift
Suppose we have a contract that requires an input body structured as follows:
Internal message structure:

op_code:uint32 
query_id:uint64 
amount:(VarUInteger 16) 
destination:MsgAddress = InternalMsgBody;
To build this message using Fift, we would use the following code:
"Asm.fif" include
"TonUtil.fif" include
smca 2drop Addr,
b>
2 boc+>B dup Bx. cr

What This Code Does:

  1. Includes Required Libraries: It imports the Asm.fif and TonUtil.fif libraries.
  2. Initializes an Empty Builder: It starts by creating an empty builder.
  3. Appends op_code: The value 24 is appended as the op_code (a 32-bit unsigned integer).
  4. Appends query_id: The value 0 is appended as the query_id (a 64-bit unsigned integer).
  5. Appends amount: The value 1 (representing 1 nanoton) is appended as the amount.
  6. Parses and Appends Destination Address: The address EQA3azUJcnicaZYflOBy_rQhhwg79_bOy9mhXt5priuc1EuX is parsed and stored in the builder as the destination. The Addr, word (defined in TonUtil.fif) is used for this, dropping unnecessary values in the process.
  7. Constructs the Cell: A cell is created from the builder’s data.
  8. Converts to Bytes: The resulting cell is serialized into a bag of cells and converted to bytes.
  9. Prints Hex Representation: The hex representation of the bytes is printed, and the result is left on top of the stack.

Running the Code in the Fift Interpreter:

When executed, the code would interact as follows with the Fift interpreter:

"Asm.fif" include

 ok

"TonUtil.fif" include

 ok

<b 24 32 u, 0 64 u, 1 Gram,

 ok

"EQA3azUJcnicaZYflOBy_rQhhwg79_bOy9mhXt5priuc1EuX" $>smca 2drop Addr,

 ok

b>

 ok

2 boc+>B dup Bx. cr

In this example, the final output is the hex representation of the constructed message, indicating successful execution of the code.

TonWeb: A Different Approach

TonWeb is a JavaScript SDK designed for The Open Network (TON). It provides a set of classes that simplify interaction with the TON ecosystem. Among these is the Cell class, which can be utilized to create a bag of cells.

JavaScript Implementation Example with TonWeb

The previous example can be accomplished in JavaScript using the TonWeb SDK as follows:

const TonWeb = require(“tonweb”);
const Cell = TonWeb.boc.Cell;
const Address = TonWeb.utils.Address;
let cell = new Cell();
cell.bits.writeUint(24, 32); // op_code
cell.bits.writeUint(0, 64); // query_id
cell.bits.writeCoins(1); // amount
let address = new Address(“EQA3azUJcnicaZYflOBy_rQhhwg79_bOy9mhXt5priuc1EuX”); // destination
cell.bits.writeAddress(address);
console.log(cell.print()); // print cell data similar to Fift
let bocBytes = cell.toBoc(false);
bocBytes.then((res) => {
console.log(Buffer.from(res).toString(“hex”));
});

When you run this script, you’ll get the following output:

This script achieves the same result as the Fift example by constructing and printing the cell data, then converting it to a bag of cells in hexadecimal format.

Constructing Complete Messages

In the previous sections, we only covered how to create message bodies. However, to construct complete messages, we need to select the appropriate message type and build it according to the TL-B Schema. Messages in the TON ecosystem come in two forms:

  1. Internal Messages: These are messages exchanged between smart contracts within the blockchain.
  2. External Messages: These are messages that either originate from outside the blockchain (Inbound External Messages or “Messages from Nowhere”) or are sent out from the blockchain (Outbound External Messages or “Messages to Nowhere”).

TL-B Schema for Message Construction

To create a complete message in the TON blockchain, you must follow the TL-B Schema for message structures. Messages can be of two types:

  1. Internal Messages: Messages exchanged between smart contracts on the blockchain.
  2. External Messages: Messages coming from or going outside the blockchain, which can either be inbound (from nowhere) or outbound (to nowhere).

Here’s the TL-B Schema for constructing a message:

message$_ {X:Type} info:CommonMsgInfo
init:(Maybe (Either StateInit ^StateInit))
body:(Either X ^X) = Message X;
int_msg_info$0 ihr_disabled:Bool bounce:Bool bounced:Bool
src:MsgAddressInt dest:MsgAddressInt 
value:CurrencyCollection ihr_fee:Grams fwd_fee:Grams
created_lt:uint64 created_at:uint32 = CommonMsgInfo;
ext_in_msg_info$10 src:MsgAddressExt dest:MsgAddressInt 
import_fee:Grams = CommonMsgInfo;
ext_out_msg_info$11 src:MsgAddressInt dest:MsgAddressExt
created_lt:uint64 created_at:uint32 = CommonMsgInfo;

Picture Getting Started with Fift: A Beginner’s Guide 4 | TON app
To build this message using Fift, we would use the following code:

“Asm.fif” include
“TonUtil.fif” include
smca 2drop Addr,
b>
2 boc+>B dup Bx. cr

Picture Getting Started with Fift: A Beginner’s Guide 5 | TON app

What This Code Does:

  1. Includes Required Libraries: It imports the Asm.fif and TonUtil.fif libraries.
  2. Initializes an Empty Builder: It starts by creating an empty builder.
  3. Appends op_code: The value 24 is appended as the op_code (a 32-bit unsigned integer).
  4. Appends query_id: The value 0 is appended as the query_id (a 64-bit unsigned integer).
  5. Appends amount: The value 1 (representing 1 nanoton) is appended as the amount.
  6. Parses and Appends Destination Address: The address EQA3azUJcnicaZYflOBy_rQhhwg79_bOy9mhXt5priuc1EuX is parsed and stored in the builder as the destination. The Addr, word (defined in TonUtil.fif) is used for this, dropping unnecessary values in the process.
  7. Constructs the Cell: A cell is created from the builder’s data.
  8. Converts to Bytes: The resulting cell is serialized into a bag of cells and converted to bytes.
  9. Prints Hex Representation: The hex representation of the bytes is printed, and the result is left on top of the stack.

Running the Code in the Fift Interpreter:

When executed, the code would interact as follows with the Fift interpreter:

"Asm.fif" include

 ok

"TonUtil.fif" include

 ok

<b 24 32 u, 0 64 u, 1 Gram,

 ok

"EQA3azUJcnicaZYflOBy_rQhhwg79_bOy9mhXt5priuc1EuX" $>smca 2drop Addr,

 ok

b>

 ok

2 boc+>B dup Bx. cr

In this example, the final output is the hex representation of the constructed message, indicating successful execution of the code.

TonWeb: A Different Approach

TonWeb is a JavaScript SDK designed for The Open Network (TON). It provides a set of classes that simplify interaction with the TON ecosystem. Among these is the Cell class, which can be utilized to create a bag of cells.

JavaScript Implementation Example with TonWeb

The previous example can be accomplished in JavaScript using the TonWeb SDK as follows:

const TonWeb = require(“tonweb”);
const Cell = TonWeb.boc.Cell;
const Address = TonWeb.utils.Address;
let cell = new Cell();
cell.bits.writeUint(24, 32); // op_code
cell.bits.writeUint(0, 64); // query_id
cell.bits.writeCoins(1); // amount
let address = new Address(“EQA3azUJcnicaZYflOBy_rQhhwg79_bOy9mhXt5priuc1EuX”); // destination
cell.bits.writeAddress(address);
console.log(cell.print()); // print cell data similar to Fift
let bocBytes = cell.toBoc(false);
bocBytes.then((res) => {
console.log(Buffer.from(res).toString(“hex”));
});

When you run this script, you’ll get the following output:

$ node message.js
x{0000001800000000000000001018006ED66A12E4F138D32C3F29C

0E5FD68430E1077EFED9D97B342BDBCD35C5739A9_}
b5ee9c7241010101003100005d0000001800000000000000001018006ed66a12e4f138d32
c3f29c0e5fd68430e1077efed9d97b342bdbcd35c5739a9ef4bc35f

This script achieves the same result as the Fift example by constructing and printing the cell data, then converting it to a bag of cells in hexadecimal format.

Constructing Complete Messages

In the previous sections, we only covered how to create message bodies. However, to construct complete messages, we need to select the appropriate message type and build it according to the TL-B Schema. Messages in the TON ecosystem come in two forms:

  1. Internal Messages: These are messages exchanged between smart contracts within the blockchain.
  2. External Messages: These are messages that either originate from outside the blockchain (Inbound External Messages or “Messages from Nowhere”) or are sent out from the blockchain (Outbound External Messages or “Messages to Nowhere”).

TL-B Schema for Message Construction

To create a complete message in the TON blockchain, you must follow the TL-B Schema for message structures. Messages can be of two types:

  1. Internal Messages: Messages exchanged between smart contracts on the blockchain.
  2. External Messages: Messages coming from or going outside the blockchain, which can either be inbound (from nowhere) or outbound (to nowhere).

Here’s the TL-B Schema for constructing a message:

message$_ {X:Type} info:CommonMsgInfo
init:(Maybe (Either StateInit ^StateInit))
body:(Either X ^X) = Message X;
int_msg_info$0 ihr_disabled:Bool bounce:Bool bounced:Bool
src:MsgAddressInt dest:MsgAddressInt 
value:CurrencyCollection ihr_fee:Grams fwd_fee:Grams
created_lt:uint64 created_at:uint32 = CommonMsgInfo;
ext_in_msg_info$10 src:MsgAddressExt dest:MsgAddressInt 
import_fee:Grams = CommonMsgInfo;
ext_out_msg_info$11 src:MsgAddressInt dest:MsgAddressExt
created_lt:uint64 created_at:uint32 = CommonMsgInfo;

Picture Getting Started with Fift: A Beginner’s Guide 6 | TON app

Constructing a Full Internal Message

To construct a full internal message, follow these steps using Fift:

"Asm.fif" include

"TonUtil.fif" include

// Message body:

<b 24 32 u, 0 64 u, 1 Gram,

"EQA3azUJcnicaZYflOBy_rQhhwg79_bOy9mhXt5priuc1EuX" $>smca 2drop Addr,

<b> constant msg_body // Define and store the message body in a constant named msg_body<b>

// Define CommonMsgInfo, starting with int_msg_info$0:

// Disable IHR, allow bounces, and mark as not bounced (binary '011')

// Use addr_none for the source address (binary '00')

// The final bitstring '011000' is appended to the builder

b{011000} s,

// Parse and append the destination address

"EQA3azUJcnicaZYflOBy_rQhhwg79_bOy9mhXt5priuc1EuX" $>smca 2drop Addr,

// Append the amount

1 Gram,

// Additional fields:

// No extra currencies, so a null dictionary is needed (binary '0')

// Zero values for ihr_fee, fwd_fee, created_lt, and created_at (overwritten later)

// Append zero bits for no init field and in-place body serialization

0 1 4 4 64 32 1 1 + + + + + + u,

// Convert msg_body cell to slice and append it to the builder

msg_body <s s b>

// Make it accessible by other contracts

dup constant internal_msg

2 boc+>B dup Bx. cr

Equivalent JavaScript Implementation with TonWeb

The same message can be constructed using TonWeb in JavaScript as follows:

const TonWeb = require("tonweb");

const Cell = TonWeb.boc.Cell;

const Address = TonWeb.utils.Address;

// Construct the message body

const body = new Cell();

body.bits.writeUint(24, 32); // op_code

body.bits.writeUint(0, 64); // query_id

body.bits.writeCoins(1); // amount

let address = new Address("EQA3azUJcnicaZYflOBy_rQhhwg79_bOy9mhXt5priuc1EuX"); // destination

body.bits.writeAddress(address);

// Construct the full message

const message = new Cell();

message.bits.writeUint(0x18, 6); // 0x18 = 0b011000

message.bits.writeAddress(address);

message.bits.writeCoins(1);

message.bits.writeUint(0, 1 + 4 + 4 + 64 + 32 + 1 + 1);

message.writeCell(body);

const bocBytes = message.toBoc(false);

bocBytes.then((res) => {

console.log(Buffer.from(res).toString("hex"));

});

Output

Running the above script will yield the following result:

b5ee9c724101010100620000bf62001bb59a84b93c4e34cb0fca70397f5a10c3841dfbfb6765ec

d0af6f34d715ce6a080800000000000000000000000000

The message we just generated is an internal message, meaning it can only be sent by contracts within the blockchain. If we need to send messages from outside the blockchain, we must create an inbound external message and deliver it to the blockchain.

For example, we can construct an external message that includes an internal message directed to our wallet’s smart contract. The smart contract will then process the internal message and forward it to the appropriate contract within the blockchain.

Example of Creating an Inbound External Message

Here’s an example of how to create an inbound external message that contains the internal message we previously constructed as its body. The recipient contract will read this body and send it as a full raw message using send_raw_message.

Fift Implementation:

"Asm.fif" include

"TonUtil.fif" include

// Import the internal message we previously created (stored as the internal_msg constant)

"internal.fif" include

<b 

// Define CommonMsgInfo for an external inbound message using ext_in_msg_info$10:

// Set the first two bits to '10' to indicate this type of message

// Use addr_none for the source address, which is '00' (indicating from nowhere)

// For the destination, use MsgAddressInt:

// addr_std$10 anycast:(Maybe Anycast) workchain_id:int8 address:bits256 = MsgAddressInt;

// Without anycast, the resulting bitstring is '100'

// Concatenating these bits gives us '1000100'

b{1000100} s,

// Parse and append the destination address (workchain_id:int8 address:bits256)

"EQBoOEfPe5LUnrXTPuUFIK9i4kMsltc63k3vFGkmbPpXcGo5" $>smca 2drop Addr,

// Append the import_fee

0 Gram,

// Process the message body:

// Append a zero bit to indicate no init field => '0'

// Append a 1 bit indicating the body is a cell reference (to fit within 1023 bits) => '1'

b{01} s,

// Append internal_msg as a cell reference

internal_msg ref,

b>

2 boc+>B dup Bx. cr

JavaScript Implementation with TonWeb:

const TonWeb = require("tonweb");

const Cell = TonWeb.boc.Cell;

const Address = TonWeb.utils.Address;

// Create the internal message body

const body = new Cell();

body.bits.writeUint(24, 32); // op_code

body.bits.writeUint(0, 64); // query_id

body.bits.writeCoins(1); // amount

let address = new Address("EQA3azUJcnicaZYflOBy_rQhhwg79_bOy9mhXt5priuc1EuX"); // destination

body.bits.writeAddress(address);

// Create the internal message itself

const message = new Cell();

message.bits.writeUint(0x18, 6); // 0x18 = 0b011000

message.bits.writeAddress(address);

message.bits.writeCoins(1);

message.bits.writeUint(0, 1 + 4 + 4 + 64 + 32 + 1 + 1);

message.writeCell(body);

// Create the external message

const ext = new Cell();

ext.bits.writeUint(0x44, 7); // 0x44 = 0b1000100

let naddr = new Address("EQBoOEfPe5LUnrXTPuUFIK9i4kMsltc63k3vFGkmbPpXcGo5"); // destination

ext.bits.writeAddress(naddr);

ext.bits.writeCoins(0);

ext.bits.writeUint(1, 2); // 1 = 0b01

ext.refs.push(message);

const bocBytes = ext.toBoc(false);

bocBytes.then((res) => {

console.log(Buffer.from(res).toString("hex"));

});

Resulting Output:

Running the above script will generate the following hex-encoded message:

b5ee9c7241010201008800014689001a0e11f3dee4b527ad74cfb941482bd8b890cb25b5ce

b7937bc51a499b3e95dc010100bf62001bb59a84b93c4e34cb0fca70397f5a10c3841dfbfb6765ecd0af6f

34d715ce6a0808000000000000000000000000000000001800000000000000001018006ed66a12

e4f138d32c3f29c0e5fd68430e1077efed9d97b342bdbcd35c5739a9a3cca5b3

These examples were basic demonstrations, but in real-world applications, messages can become much more intricate. For instance, external messages need to be signed, and the signature must be included so that the smart contract can authenticate the sender and execute the message. Additionally, more advanced control structures can be implemented in Fift, such as conditions, loops, and more. For example, we could programmatically check if a cell can be serialized in-place and adjust the process accordingly.

Utilizing these features allows us to create more versatile and reusable Fift scripts. More complex messaging structures and advanced control flows in Fift will be discussed in the upcoming sections.