# Introduction

**fi** is a statically typed high-level programming language designed to be similar, syntactically, to ECMAScript/Javascript and Solidity. fi compiles directly to valid and well-typed Michelson code, the native smart contract language for the Tezos block chain.

fi allows developers to work in a more familiar coding environment, providing a close experience to object-oriented programming. Here's a really short demonstration of the potential of developing smart contracts with fi:

```javascript
# King of Tez Contract

# Define a constant for ONEWEEK in seconds
const int ONEWEEK 604800;

# Define an object King
struct King(
    timestamp end, 
    mutez bounty, 
    address owner); 

# Declare a storage variable king of type King (the object we created)
storage King king; 

# Entry point for this script
entry contend(){
    assert(storage.king.end < NOW || AMOUNT > storage.king.bounty);
    let address oldKing = storage.king.owner;
    storage.king = new King(add(NOW, ONEWEEK), AMOUNT, SENDER);
    transfer(oldKing, AMOUNT);
}
```

This smart contract reads extremely easy within fi, but accomplishes an extremely advanced set of functions.

## Compiling to Michelson

You can install our compiler by following instructions from our [Github repo](https://github.com/TezTech/fi-compiler) - this will allow you to install and use our compiler. You can also use our [online compiler tool](https://fi-code.com) as well.

The web-based browser/editor will compile your fi to Michelson and typecheck the compiled source code. Furthermore, you can run tests against your Smart Contract to simulate live operations and calls.


# Contract Definitions

The basic structure of a smart contract written is fi is fairly simple, and takes a similar approach to other object-oriented languages. The core definitions include Constants, Storage Variables, Structs and Contract Entry Points.

Furthermore, we are also working on additional definitions for internal functions and response functions (for contract to contract communication via a promise-like system).

## Constants

Constants can be defined and reused throughout your code like any other global constant. Constants can only be defined as [basic types.](/overview/types)

**const \<type\*>  \<constant name> \<literal value>;**

```
const int ONEHOUR 3600;
```

## Storage Variables

Storage variables are permanently stored within the block chain and represent the state of the contract. Storage variables can be of any type (basic and complex, as well as custom types defined as structs).

These variables must be defined, and can be accessed via the storage object:

**storage \<type|struct> \<variable name>;**

Which can then be accessed via the storage object:

**storage.\<variable name>**

```javascript
storage int counter; 
#Storage variable named counter, accessed via storage.counter

entry increaseCounter(){
    storage.counter.add(int 1);
}
```

## Structs

Structs allow you to define more complex custom types to be used within fi. Once a struct has been declared, it can be used as a variable type.

**struct \<struct name>(\<typed variables>)**

Where typed variables is a list of arguments defining the type and name of each variable:

**\<type|struct> \<variable name>, ...**

You can declare a new instance of type object using the new keyword, followed by the object name.

```
struct Person(
    string name,
    int age,
    string favouriteFood
);

storage Person me;

entry add(string name, int age, string food){
    storage.me = new Person(input.name, input.age, input.food);
}
```

Struct variables can be accessed using a fullstop/dot - this can traverse recursively:

```
entry changeName(string name){
    storage.me.name = input.name;
}
```

## Entry Points

Entry Points define the public calls that can be made to a smart contract written in fi. A smart contract can contain multiple entry points, each of which needs to be declared using the entry keyword followed by a name and optional input variables within a set of parenthesis. \
\
**Input variables**\
Input variables are a list of typed variables, similar to declaring a struct. This declaration can be blank, i.e. () .

**\<type|struct> \<variable name>, ...**

Input variables can then be accessed via the input variable:

**input.\<variable name>**

**\*Note: At least one entry point must be defined for a contract to compile correctly.**

```
entry add(string name, int age, string food){
    storage.me = new Person(input.name, input.age, input.food);
}
```


# Basic Types

fi is a statically typed language, where a variable must be typed on declaration and that type cannot change. When you are setting a variable to a literal value, you must also ensure the type is declared.

```
storage nat Foo;

entry Test(int Bar){
    let string Hello = string "World"; 
    #We must declare the type of all literals
}
```

During compilation, types are strictly checked and enforced. These types reflect the native Michelson types. All available basic types are defined below:

## Boolean

**bool** - possible values being either **true** or **false**.

```
let bool available = bool true;
```

## Integers & Natural Numbers

Integers and naturals are arbitrary-precision, meaning the only size limit is fuel. The only difference is that Natural Numbers are unsigned.

**int** - possible values being any integer value (negative and positive)\
**nat** - possible values being any positive integer value

```
let nat n1 = nat 1;
let nat n2 = nat 2;
let nat n3 = sub(n1, n2); # Fail - must be declared as an int
let int n4 = sub(n1, n2); # OK
let nat n5 = to_int(sub(n1, n2)); # Also OK
```

**Note: Some arithmetic functions will return a different type based on the input types. You can use to\_\* functions if you need to typecast a specific value.**

## Strings

Strings are used to hold a value in text form.

**string** - possible value being anything, but must be encompassed by double-quotes **"text"**

```
let string name = string "John";
```

## Mutez

Mutez is the native Michelson type for defining a variable to represent a mutez, the native currency of Tezos in its smallest denomination (e.g. 0.000001 tez).&#x20;

> Mutez are internally represented by a 64 bit signed integer. There are restrictions to prevent creating a negative amount of mutez. Operations are limited to prevent overflow and mixing them with other numerical types by mistake. They are also checked for under/overflows.

**mutez** - possible values being any positive integer value

```
let mutez amount = mutez 100000000;
```

## Timestamp

Timestamps represent a date/time value.

**timestamp** - valid RFC 339 notation, encompassed by double-quotes, or alternatively number of seconds since Unix Epoch.

```
let timestamp today = timestamp "2019-02-20 00:00:00";
let timestamp alsotoday = timestamp 1550638795;
```

## Address

Addresses are untyped native contract addresses stored on the Tezos blockchain.&#x20;

**address** - must be a valid public address and must be provided in the base58-check encoded version encompassed by double quotes (e.g. "KT1...", "tz1...").

```
let address payee = address "tz1...";
```

## Public Key

Public keys are used for verifying a signed message using the verify function, or can be converted to a public key hash (pkh/key\_hash) and used for on-chain operations (delegation, origination and transfer).

**key** - must be a valid public key, encompassed by double quotes, in the base58-check encoded format (e.g. "edpk...", "p2pk")

```
let key signer = key "edpk...";
```

## Public Key Hash

Public key hashes are the hashed form of a key, and can also be used to create an implicit contract (and therefore address using typecasting). This type can be declared as key\_hash or via an alias, pkh.

**key\_hash|pkh** - must be a valid public key hash, encompassed by double quotes, in the base58-check encoded format (e.g. "tz1...", "tz2...").

```
let key_hash signer = pkh "tz1...";
```

## Signature

Signatures are base58-check encoded signatures (e.g. "edsig..."). These can be generated by the node-client to sign a message with a users private key. This can then be verified within fi using the verify function.

**signature** - must be a valid base58-check encoded signature, encompassed by double-quotes "..."

```
let signature sig = signature "edsig...";
```

## Bytes

Bytes are defined as hexadecimal, and can be used for multiple purposes.

**bytes** - must be valid hex, starting with 0x. This should not be wrapped in double quotes;

```
let bytes b = bytes 0x08aa28;
```


# Complex Types

As well as the basic types, fi also allows the following complex types which usually work in conjunction with other types. Complex types can't be used in a literal way and have specific constructors for creating new variables.

## Maps

Maps require a key and an element, and can form a large list of mapped elements. Keys must be unique for each entry, and can be used to retrieve a specific entry for a map.

A map key must be one of the following types:

* string
* bool
* int
* nat
* bytes
* mutez
* timestamp
* address
* key\_hash/pkh

We define the map type in the following way:

```
storage map[address => nat] balances;
```

This creates a map type variable, with a map key of type address, and a map item of type nat, stored as storage.balances.

### Empty Map

An empty map can be defined using the following:

```
let map[int=>string] passages = new map(int, string);
```

### Operations

The following operations can be used with maps

* **in(map, map\_key)** - returns bool if key exists as a map key in the map
* **length(map)** - returns cardinal size of the map as a **nat**
* **get(map, map\_key)** - returns item with index key. Fails if key doesn't exist (it is advised to use in first)
* **push(map, map\_key, map\_item)** - no return. Pushes item into map at index key. Will add the element if key doesn't exist, and update if it does (acts as an upsert)
* **drop(map, map\_key)** - no return. Removes the key/element pair from the map&#x20;

**These functions can be used as standalone functions, or as a** [**variable modifier**](/overview/variable-modifiers)**.**

```
let map[int => string] textMap = new map(int, string);
push(textMap, int 1, "One");
textMap.push(int 2, "One"); // Same as above
```

## Big Map

Big maps work the same as normal maps, but have a few restrictions:

1. Big maps can only be declared as a storage variable
2. Only one big\_map can exist for any given contract
3. The length() function doesn't work with big\_maps
4. Big maps can't be constructed

We define the map type in the following way:

```
storage bmap[address => nat] balances;
```

All functions, other then length, are applicable for big maps.

## Lists

Lists are non-indexed arrays of a specified type, and are defined as follows:

```
let string[] names;
```

This creates a list of the specified type - in this instance a list of strings, which can be accessed via storage.names.

### Empty list

An empty map can be defined using the following:

```
let string[] names = new list(string);
```

### Operations

The following operations are available for lists:

* **length(list)** - returns cardinal size of a list as a nat
* **push(list, item)** - pushes an item to a list
* **pop(list)** - removes the last item from a list and returns it

**These functions can be used as standalone functions, or as a** [**variable modifier**](/overview/variable-modifiers)**.**

```
let string[] names = new list(string);
push(names, "John");
names.push("Bill"); // Same as above
```

## Set

Sets are similar to lists as we store a single type of data per entry, and can be declared as follows:

```
storage set[nat] numbers;
```

The set item type must be one of the following types (same as the map key):

* string
* bool
* int
* nat
* bytes
* mutez
* timestamp
* address
* key\_hash/pkh

### Operations

The following operations are available for lists:

* **length(set)** - returns cardinal size of a set as a **nat**
* **push(set, item)** - pushes an item to a set
* **in(set, item)** - returns bool if item exists in the set
* **drop(set, item)** - no return. Removes the item from a set&#x20;

**These functions can be used as standalone functions, or as a** [**variable modifier**](/overview/variable-modifiers)**.**

```
let set[string] names = new set(string);
push(names, "John");
names.push("Bill");
```

## Contract

The contract type is the typed version of an address. Michelson contract types must also specify the type of the input parameter.

```
let contract[unit] implicit = to_contract(address "tz1...");
```

## Option

Optional values can be set and then used within expressions. These values either hold "some" value, or "none". Optional values are defined by adding a question mark before another type:

```
let ?nat optional = to_optional(nat 100);
```

We can convert any existing value to an optional value using the **to\_optional** cast, or we can use the **none** function to create an optional variable with no value.

```
let ?bool test = none(bool);
if (isset(test) == false) {
    #This will execute
}
```


# Control Structures

The following control structures can be used in fi:

* if/else
* throw
* assert

We are currently working on a few additional control structures, including:

* foreach
* loop

## If/else

**If** statements allow you to branch your logic in multiple ways based on the resolution of an expression. If the expression resolves as true, the code within the curly braces is executed.

```
if (SENDER == address "tz1NhSA8NV4W3e5ws37u1xzjkgxDCpijyh7m" || OWNER == SENDER) {
    
}
```

### else

A second block of code can be placed within curly braces after the initial block, prepended with the else control. You can also use **else if** to define another condition expression to evaluate.

```
if (SENDER == address "tz1NhSA8NV4W3e5ws37u1xzjkgxDCpijyh7m") {
    return.isOwner = bool True;
} else if (nat 2 == add(nat 1, to_nat(sub(nat 5, int 2, nat 2)))){

} else {

}
```

## Throw

This allows the developer to exit execution of the script - an optional value can be provided as an argument, which will be returned as an error.

```
if (SENDER != SOURCE){
    throw(string "Error with sender");
}
```

## Assert

The assert allows the developer to exit execution if a condition returns false - essentially the combination of an if and a throw. The first argument must be the condition to evaluate, and the optional second argument can be the value to be returned as an error. The previous example can also be written as:

```
assert(SENDER == SOURCE, string "Error with sender");
```


# Local Variables

In fi, local variables, or temp variables, can be declared within the root section of a contract entry. These variables are perfect for non-state related variables that you need to use on the fly during the execution of your contract. This is done by declaring the variable and type. This type is static and can't be changed.

**let \<type|struct> \<variable name> = \<value>;**

Value must evaluate to a compatible type. Once defined, these variables can be access via their name:

**\<variable name>**


# Functions

In fi, all variables are modified using strict functions. For example, you can't use a normal coding expression like this in fi:

```
let int test = int 20 + int 10 - int 5;
```

Instead, we must use functions, for example:

```
let int test = sub(add(int 20, int 10), int 5);
```

With fi, all returned values MUST be used. For example:

```
let int test = int 20;
add(test, int 10); #Invalid, as int 30 is returned and unused
test.add(int 10); #Valid

```

This returns a value of int 30 which is left unused and will cause a compilation error.&#x20;

## **Arithmetic functions**

### add(mixed,...) returns mixed

Returns the sum of two or more provided arguments, starting from left to right.&#x20;

```
let nat test = add(nat 1, nat 2, nat 3, nat 4); # Returns nat 10
```

The Return type is defined by the inputs between the two values being evaluated:

```
add(int, int, ...) 				=> int
add(int, nat, ...) 				=> int
add(nat, int, ...) 				=> int
add(nat, nat, ...) 				=> nat
add(mutez, mutez, ...) 		    => mutez
add(timestamp, int, ...) 	    => timestamp
add(int, timestamp, ...) 	    => timestamp
```

**This function can be used as standalone functions, or as a** [**variable modifier**](/overview/variable-modifiers)**.**

### sub(mixed,...) returns mixed

Returns the difference of two or more provided arguments, starting from left to right.

```
let int test = sub(nat 10, nat 5, nat 3, nat 1); # Returns int 1
```

The Return type is defined by the inputs between the two values being evaluated:

```
sub(int, int, ...) 				=> int
sub(int, nat, ...) 				=> int
sub(nat, int, ...) 				=> int
sub(nat, nat, ...) 				=> int
sub(mutez, mutez, ...) 			=> mutez
sub(timestamp, int, ...) 		=> timestamp
sub(timestamp, timestamp, ...) 	=> timestamp
```

**This function can be used as standalone functions, or as a** [**variable modifier**](/overview/variable-modifiers)**.**

### mul(mixed,...) returns mixed

Returns the product of two or more provided arguments, starting from left to right.

```
let nat test = mul(nat 10, nat 5, nat 3, nat 1); # Returns nat 150
```

The Return type is defined by the inputs between the two values being evaluated:

```
mul(int, int, ...) 			=> int
mul(int, nat, ...)		    => int
mul(nat, int, ...) 	    	=> int
mul(nat, nat, ...) 			=> nat
mul(mutez, nat, ...) 		=> mutez
mul(nat, mutez, ...) 		=> mutez
```

**This function can be used as standalone functions, or as a** [**variable modifier**](/overview/variable-modifiers)**.**

### div(mixed,...) returns mixed

Returns the product of two or more provided arguments, starting from left to right.

```
let nat test = div(nat 100, nat 5, nat 10, nat 1); # Returns nat 2
```

The Return type is defined by the inputs between the two values being evaluated:

```
div(int, int, ...) 			=> int
div(int, nat, ...)		    => int
div(nat, int, ...) 			=> int
div(nat, nat, ...) 			=> nat
div(mutez, nat, ...) 		=> mutez
div(mutez, mutez, ...) 	    => nat
```

**This function can be used as standalone functions, or as a** [**variable modifier**](/overview/variable-modifiers)**.**

### mod(mixed,...) returns mixed

Returns the remainder/mod of two or more provided arguments, starting from left to right.

```
let nat test = div(nat 100, nat 5, nat 10, nat 1); # Returns nat 2
```

The Return type is defined by the inputs between the two values being evaluated:

```
div(int, int, ...) 			=> int
div(int, nat, ...)		    => int
div(nat, int, ...) 			=> int
div(nat, nat, ...) 			=> nat
div(mutez, nat, ...) 		=> mutez
div(mutez, mutez, ...) 	    => nat
```

**This function can be used as standalone functions, or as a** [**variable modifier**](/overview/variable-modifiers)**.**

### **abs(int) returns nat**

Returns the absolute value (unsigned) of the input int, returned as a nat.

```
let nat test = abs(int -20); # Returns nat 20
```

### neg(nat|int) returns int

Returns the negative signed value of the input, as an int.

### sqr(mutez|nat|int) returns \[same as input]

Returns the sqr of the input variable as the same type.

```
let nat test = sqr(nat 10); #Returns 100
```

## String & Byte functions

### concat(bytes|string,...) returns  \[same as input]

Returns the concatenated inputs as the same output type. When using concat, all arguments must be of the same type (either bytes or string). Similar to arithmetic functions, multiple inputs can be concatenated from left to right.

```
let string HelloWorld = concat(string "Hello", string " ", string "World");
```

**This function can be used as standalone functions, or as a** [**variable modifier**](/overview/variable-modifiers)**.**

### concat\_ws(string seperator, string...) returns string

Returns the concatenated inputs using the first string as a separator.

```
let string HelloWorld = concat(string " ", string "Hello", string "World");
```

### slice(string|bytes, nat offset, nat length) returns \[same as first argument]

Returns the slice string or bytes starting from offset for length.

### hash(bytes, ?algo) returns bytes

Returns the hashed bytes using the algorithm matching algo. Algo can be set to one of the following literals:

* blake2b
* sha256
* sha512

If algo isn't provided, blake2b will be used by default.

```
let bytes test = hash(bytes 0x050000, sha512);
```

### pack(data) return bytes

Data of any type can be packed into byte form, which can be used for other purposes (as well as unpacking).

```
let bytes test = pack(nat 1);
```

### unpack(bytes, type) return mixed

The opposite to unpack - the packed bytes must be provided, as well as the type of the packed data. Will return the unpacked bytes as type.

```
let bytes test = pack(nat 1);
let nat test2 = unpack(test, nat);
```

### verify(bytes, signature, key) returns bool

Verify will evaluate if the signature matches the provided key and bytes. Returns a bool.

## Map/Set/List functions

**All of these functions can be used as standalone functions, or as a** [**variable modifier**](/overview/variable-modifiers)**.**

### in(map|bmap|set, mixed val) returns bool

For map and bmap, returns true if mixed val is a valid key that exists within the map/bmap, otherwise returns false. For sets, this returns true if val is a vlid element that exists within the set.

```
let set[int] tset = new set(int);
let bool test = tset.in(int 1); # False
```

### length(map|list|set) returns nat

Returns the cardinal length/size of the map, list or set as a nat.

```
let set[int] tset = new set(int);
let nat test = tset.length(); # nat 0 
```

### get(map|bmap, mixed val) returns mixed

Returns the element and type that corresponds to the map key val, or fails if it doesn't exist. We recommend using the in function first.

```
let map[int=>string] tmap = new map(int, string);
let string test = tmap.get(int 1); # Will throw an error
```

### push(map|bmap, mixed key, mixed val) no return

Inserts or updates the element val with key. Does not return anything.

```
let map[int=>string] tmap = new map(int, string);
tmap.push(int 1, "Hello World");
let string test = tmap.get(int 1); # string "Hello World"
```

### push(set, mixed val) no return

Inserts or updates the element val. Does not return anything.

```
let set[string] tset = new map(string);
tset.push("Hello World");
```

### drop(map|bmap|set, mixed val) no return

For maps and big maps, the element with the corresponding map key val is removed from the map. For sets, the element val is removed. Does not return anything.

```
let set[string] tset = new map(string);
tset.push("Hello World");
tset.drop("Hello World");
```

### pop(list) returns mixed

Returns the last item and type from list.

```
let string[] tlist = new list(string);
tlist.push("Hello");
tlist.push("World");
let string test = tlist.pop(); # string "World";
```

## On-chain functions

### transfer(address|pkh|key\_hash|key|contract \*, mutez, ?data) no return

Executes an on-chain operation to the provided address sending amount mutez. If data is present, we also send this as the parameter. The contract type must match the type of the data (if provided).

Nothing is returned.

```
transfer(SENDER, mutez 10);
```

### delegate(?key\_hash) no return

Sets the delegate for the contract - if key\_hash is set than this is used, otherwise the contract is un-delegated if no argument is provided.

Nothing is returned.

```
delegate();
```

## Other functions

### isset(?mixed) returns bool

Returns true if the optional value is not empty, otherwise it returns false.

```
let ?string test = to_optional(string "Hello World");
let bool test2 = isset(test); # True
```

### none(type) returns ?type

Returns an optional value of type that is empty.

```
let ?string test = none(string);
let bool test2 = isset(test); # False
```


# Type Casting

Although fi types can be confusing, we've implement a number of typecasting functions to help ensure typing is clean and consistent.

**to\_address** -  converts a contract, key, pkh/key\_hash to an address

**to\_int** - converts mutez or nat to an int

**to\_mutez** - converts nat or int to mutez

**to\_nat** - converts mutez or int to nat

**to\_optional** - converts any type to an optional version of that type

**to\_pkh** - converts a key to a key\_hash/pkh

**to\_some** - converts an optional type to a normal type (throws an error if the value is an empty optional value)

**to\_contract** - converts a key, pkh/key\_hash or address to a contract unit. If a second type argument is provided, will type cast an address to a typed address of matching type.


# Variable Modifiers

Variable modifiers allow you to work directly with a variable, making your code look more logical and easier to follow, as well as taking less time to type out. A variable modifier would look like this:

**\<variable>.\<modifier>(\<arguments>);**

```
let int n1 = int 1;
n1 = add(n1, int 3); # n1 = 4

# We can use a variable modifier here instead
let int n2 = int 1;
n2.add(int 3); // n2 = 4
```

Variable modifiers still execute the original functions (i.e. the above is using the add() function), although **we drop the first argument** of the function and ensure all other arguments are provided.

In some cases, variable modifiers will also store the result directly to the original variable as well, therefore the following is invalid:

```
let int n1 = 1;
let int n2 = n1.add(int 3); // Error - n1 = 4, n2 = compile error

//Instead you would do the following
let int n1 = 1;
let int n2 = add(n1, int 3); // n1 = 1, n2 = 4
```

The following [functions](/overview/functions) are acceptable variable modifiers (ensure the types are correct):

* **add**
* **sub**
* **mul**
* **concat**
* **mod**
* **div**
* **length**
* **get**
* **pop**
* **drop**
* **in**
* **push**


# Global Constants

The following global constants can be used throughout your smart contract.

* AMOUNT - returns **tez**, amount of the current transaction
* BALANCE - returns **tez**, amount held by the current contract
* NOW - returns **timestamp**, current date time
* STEPS - returns **nat**, number of steps until end of script execution
* SELF - returns **contract**, pointer to current contract
* SOURCE - returns **address**, the address of the original contract source
* SENDER - returns **address**, the address of the current transaction source
* OWNER - returns **address**, the address of the current contract


# Examples

Coming soon


