---
# System prepended metadata

title: Formation tezos

---

---
title: Formation tezos
tags: tezos, formation
robots: noindex, nofollow
author: Julien Noyer
---

# Formation tezos

![](https://hackmd.io/_uploads/Skg1gBtea.png)

>  A blockchain designed to evolve

## Tezos introduction

The first step after the ⁠Aucun accès , is for you to watch this introduction video on Tezos:
https://youtu.be/dNpzmAO2vLs
If you are here on time, we will have a live discussion about a few minutes later.
Note that the notion of rolls mentioned in the video is now deprecated, and the minimum for baking is now 6000 tez.
Tezos evolves fast, so sometimes the videos are a bit obsolete as we don't redo them every time there is a change. This means that when we present commands, you should always use the version of the commands from the cheat-sheets we share with you, that we keep up to date, rather than just copy from the videos.
Use the video for understanding the concepts first, then use the cheat-sheet for the exact syntax.

## 1 Octez client

Warning: as soon as the video shows you how to configure the gitpod settings, pause the video and do it, so that the gitpod may load.

Here is the link. Don’t open it until you have changed your settings.

https://gitpod.io/#https://gitlab.com/nomadic-labs/training-gitpod

Warning: don’t copy the commands by hand from the videos. Instead, use the ones provided in the cheat sheet, to make sure you don’t make mistakes, and the version you use is up to date.

Watch the video on Octez client: https://www.youtube.com/watch?v=3sLUdnyhLM0

Please note that tezos-client  has been renamed octez-client, but the video has not been updated since the name change.

Here is a link to the Octez Client Cheat Sheet: 
https://docs.google.com/document/d/1K3D0tZFw40-rH3gBhjVVLuP3gRrHL922YvSz85svMgg/edit?usp=sharing

**Exercise Client.1**

Configure your octez client as shown on the video:

- select VS Code for Browser as your IDE in gitpod settings
- open a new gitpod workspace
- point your octez-client to the correct endpoint (see cheat sheet)
- create an account
- use a faucet to send tez to your account
- observe this account on tzkt.io (select ghostnet in the top-left corner)
- share the public key hash of your account, with other participants (it starts with tz1)
- setup some contract aliases on the accounts of other participants
- setup environment variables, and a configuration file

If you have some experience with the command line etc. We advise to try to do this just based on what you saw on the video and looking up the different commands in the Cheat Sheet.
On the other hand, if you are less experienced, or if you are struggling, you can follow this detailed step by step tutorial: https://docs.google.com/document/d/1IE-kvRfGcJi4ECiGymNZvJoMvcPxquf4FnQcFWVFLDA/edit?usp=sharing

Please post your tz1 address here as soon as you activated your account on ghostnet

## 2 Calling a contract

Video on calling a smart contract: https://youtube.com/watch?v=2-Q7wEUK7CA

**Exercise Call.1**

transfer some tez to different participants, and let them know by posting a message here

**Exercise Call.2**

Contract: KT1CENSNCADcnQUauEiTBNYcSabxcYBAKwsJ

set an alias for the first contract. This contract just replaces the storage with a value
call it with an integer parameter
observe the effect on Better Call Dev

**Exercise Call.3**

- Contract: KT1L8cMTbxGtQnqYQ2sA555cBLLuVfFxoRrM
- set an alias for the second contract. This contract adds a string at the end of the storage
- add your name to that storage
- observe the effect on https://better-call.dev/. See the other people calling it too.

Just like before, if you have some experience with using a command line, we advise you to try just based on what you understood from the video, and with the help of the cheat-sheet (from the previous channel).

On the other hand, if you are less experienced or ar stuck, you can follow this detailed tutorial: https://docs.google.com/document/d/1w3JgsXX7DM9myF4T_xoks9fmmFH0IE7nqoup6JlkPxU/edit?usp=sharing

### Exercice

Pour intéragir avec la blockchain, vous devez créer un compte client avec la commande : 

```bash=
octez-client gen keys <user-name>
```

Vous pouvez ensuite vérifier la création de votre compte client avec la commande : 

```bash=
octez-client show address <user-name>
```

Ce qui donne pour résultat : 

```bash=
Account: <user-name>
Hash: tz1UdrUPXH6nMZNB2KH7SAFsgz2H4CvjLTJ1
Public Key: edpkvDrJdeLb3wBT7akJ38bXWZfYzd76ur3Bz87k4S6F6hzkXXVykw
```

Le compte ainsi créé peu recevoir des ꜩ, afin de continuer les exercices, vous devez vous rendre sur le site https://faucet.ghostnet.teztnets.xyz afin de créditer votre compte. Une fois votre compte créditer, vous pouvez vérifier votre "balance" en tapant la commande suivante : 

```bash=
octez-client get balance for <user-name>
```

Ce qui donne pour résultat : 

```bash=
2901.912645 ꜩ
```

Il est également possible d'optenir plus d'information sur votre comte en vous rendant sur le service en ligne https://ghostnet.tzkt.io. Vous devez vérifier que la chaine utilisée est "Ghostnet" avant de renseigner le "hash" - nommé "address" - dans le formulaire dédié.

![](https://hackmd.io/_uploads/HkSI2-dlp.png)

Afin de d'appeler un contrat vous devez dans un premier temps le créer avec la commande suivante : 

```bash=
octez-client remember contract <contract-name> <user-or-contract-address>
```

Il est ensuite possible d'exécuter le contrat avec la commande : 

```bash=
octez-client --wait none transfer 5 from <user-name> to <contract-name>
```


## 3 Deploy a contract

Video on deploying a smart contract: https://youtube.com/watch?v=EjDkB8vjr7g

**Exercise Deploy.1**

Deploy and call a copy of the contract at address KT1L8cMTbxGtQnqYQ2sA555cBLLuVfFxoRrM

Use better call dev to find its Michelson code.

Note that this is the second contract from the previous exercise.

Try to do it using only what you learned from the video and the cheat-sheet.
If you are struggling, you can follow this detailed tutorial: https://docs.google.com/document/d/13pMWEgZbdBME1ZN8s4M6ofZJOHwq94xOlLhMBB-ncaw/edit?usp=sharing

### Exercice

La définition d'un contrat ce fait dans un langage spécifique dont voiçi un exemple : 

```bash=
{  parameter (or (int %decrement) (int %increment)) ;
   storage int ;
   code { UNPAIR ; IF_LEFT { SWAP ; SUB } { ADD } ; NIL operation ; PAIR } 
}
```

Cette exemple provient de la formation, il faut créer un fichier dans votre répertoire contenant le code ci-dessus nomé `contract.test.tz`, avant de le déployer avec la commande suivante : 

```bash=
octez-client originate contract <contract-name> transferring 0 from <user-name> running contract.test.tz --init '0' --burn-cap 0.1
```

> L'exention `.tz` est spécifique à la chaine Tezos.

Pour vérifier le déploiement de votre contract, vous devez vous rendre sur le service en ligne https://better-call.dev pour rechercher le hash de votre contrat dans le formulaire dédié.


## 4 Choice of language

Ligo presentation: https://youtube.com/watch?v=z6WAwA1p2jA?v=2-Q7wEUK7CA

SmartPy presentation: https://www.youtube.com/watch?v=fhsIBN1HMOs

Archetype presentation: https://youtube.com/watch?v=b0_weuzwvOM
The same contract in three languages :

![](https://hackmd.io/_uploads/BylhtZOgp.png)

Here is an extra slide about Archetype projects, that I didn't get to include in the video:

![](https://hackmd.io/_uploads/By6htWOep.png)

The same contract as above, but in the latest version of SmartPy, which is the one we will use for this training. The presentation video hasn't been updated yet, but the rest of the content for smartpy is new.

![](https://hackmd.io/_uploads/S1PatZ_gp.png)

Once you pick your language, please post a message in the corresponding channel 5, saying "I pick [name of language]", so that the corresponding team knows to follow you.

It's best if participants are spread between different languages, so that everyone can get help. All are good languages, and most of what you learn with one language are concepts that apply to all languages, so it makes it easy to try another language later if you like. There is no risk of really making the wrong choice.

Don't hesitate to ask any questions you may have about the languages here, before you make your choice. 

## 5 Archetype first contract

Archetype first Contract Video: https://www.youtube.com/watch?v=_AbSZeo6onU

Cheat-sheet Archetype: https://docs.google.com/document/d/1ptmayOVtG9spJdF8dPvArfAOfevmYMBflTWwm2g_cts/edit?usp=sharing

**Exercise First.1**

Test the example contract "examples/counter" from gitpod

**Exercise First.2**

Create a contract that has a string as storage.

The contract should take a string as a parameter.

When called, it should add a comma and this parameter, at the end of the storage.

Test this contract. Make sure you check the syntax for passing a parameter to your entry point.  (see in cheat-sheet, ({ arg : {[param]: [value] })

**Exercise First.3**

Change the contract from the previous exercise, by adding to the Storage, the number of times that it was called.

For example, at first, the contract may contain “Hello” and 0. Then after a call with the parameter “John”, it will contain “Hello,John” and 1. Then after another call, “Hello,John,Jennifer” and 2.

Test this contract.

## 5 JSLigo first contract

SLigo first Contract Video: https://youtube.com/watch?v=gu8VMCZkrug

Cheat-sheet JSLigo: https://gl.githack.com/ligo.suzanne.soy/training-gitpod/raw/master/cheat-sheet-jsligo.html

**Exercise First.1**

Using dry-run, test the example contract "examples/counter" from gitpod
Then compile it to look at the corresponding Michelson contract.

**Exercise First.2**

Create a contract that has a string as storage.

The contract should take a string as a parameter.

When called, it should add a comma and this parameter, at the end of the storage.

Test this contract.

**Exercise First.3**

Change the contract from the previous exercise, by adding to the Storage, the number of times that it was called.

For example, at first, the contract may contain “Hello” and 0. Then after a call with the parameter “John”, it will contain “Hello,John” and 1. Then after another call, “Hello,John,Jennifer” and 2.

Test this contract.

**Warning**

With dry-run, you can’t run a succession of tests where each test makes a call based on the result of the previous test. Every time, you need to provide the new value of the storage, that was produced by the previous call. We will later see a more advanced way to do tests.

## 5 JSLigo first antrypoints

Vidéo JSLigo on entry points : https://youtube.com/watch?v=DBk8frVMBKc

**Exercise Compile.1**

Write and compile a contract with two entry points into Michelson. Each entry point should have a parameter of a different type.

Compile the initial storage of this contract.

Originate it with the compiled initial storage

Call it after compiling the parameter.

## 5 Smartpy first contract

Video on first contracts in Smartpy: https://youtu.be/5hg5EykWLII

Here is the example FlipValue contract presented in the course:

```python=
import smartpy as sp

@sp.module
def main():

    class FlipValue(sp.Contract):
        def __init__(self):
            self.data.side = 0
        
        @sp.entrypoint
        def flip(self):
            self.data.side = 1 - self.data.side

@sp.add_test(name = "Testing")
def test():
    scenario = sp.test_scenario(main)
    c1 = main.FlipValue()
    scenario += c1
    scenario.h2("Testing flip entrypoint")
    scenario.verify(c1.data.side == 0)
    c1.flip()
    scenario.verify(c1.data.side == 1)
    c1.flip()
    scenario.verify(c1.data.side == 0)
    c1.flip()
    scenario.verify(c1.data.side == 1)
```

Test it at https://smartpy.io/ide, then use it as inspiration create your own smart contract :
- call it CountTheCalls
- the storage should contain a value nb_calls, initialized with 0
- increment this value every time this contract is called, through an entrypoint named make_call()
- add a test scenario and run it
- show us your solution in your private channel by using the share link of the smartPy IDE

Here is the cheat-sheet where we include all the syntax elements we use during the training, for SmartPy:

https://docs.google.com/document/d/14PTzLLA2blhI39FbmZ99068CG-dKQrupMsyaArGQ9SI/edit?usp=sharing

## 5 Smartpy types
Video on types in SmartPy: https://youtu.be/w33axEyIdp0

This contract doesn't compile. Fix the issue and make it compile:

```python=
import smartpy as sp

@sp.module
def main():

    class StoreValue(sp.Contract):
       def __init__(self):
           self.data.storedValue = 24
    
       @sp.entrypoint
       def add(self, a):
          self.data.storedValue += a
    
       @sp.entrypoint
       def sub(self, b):
           self.data.storedValue -= b

@sp.add_test(name = "Testing")
def test():
   scenario = sp.test_scenario(main)
   contract = main.StoreValue()
   scenario += contract
   scenario.h3(" Helping type inference ")
   contract.add(sp.nat(5))
   contract.sub(5)
```


Then, add a multiply entrypoint:
- it should take a parameter called factor of type int.
- it should multiply the value of the storage by this parameter

- Finally, add corresponding tests to your scenario.
Reminders:
- There are two types on Tezos to manipulate simple numbers: sp.int and sp.nat sp.nat are for non-negative values
- there is no upper limit (or lower limit for sp.int), so no risk of overflow errors, but using storage costs tez
- there are no floating point numbers on Tezos. This is on purpose, to avoid any rounding issues 
- we can convert nat into int using sp.to_int(value)
- we can convert a postitive int into nat using sp.as_nat(value)
- Type inference can infer the types of values based on:
    - the initial value assigned to the storage
    - values passed as parameters in tests
    - operations applied to parameters
- There are sveral ways to help type inference:
- add information about the type of a parameter, using sp.cast(name, type) within an entrypoint
- provide the type values in the storage or parameter calls using sp.int(5) or sp.nat(5)

## 5 Smartpy strings

Video on Strings in SmartPy: https://youtu.be/zULCqux6-cw

To illustrate the concepts of eternity and immutability, create this smart contract:

- Name the contract EndlessWall
- The  storage should contains a  field wallText of type string
- Add an entrypoint write_message that takes a parameter message of type string
    - It should add a comma, then the message, then the string " forever" to the storage.
    - Example: if the storage is "Hello" and we call write_message("Tezos"),
    - The new storage should become "Hello, Tezos forever”
    - Create a corresponding test scenario


Reminders:
- string literals are simply written between double quotes like this: "Tezos"
- On Tezos, strings may only contain pure ASCII characters. No accents / unicode. This is on purpose.
- You may simply use the + operator to concatenate strings
- the name of the type is sp.string, but you probably won't need to specify it

## 6 JSligo verification

JSLigo Video on verifications: https://youtube.com/watch?v=5tCBOzGyEbM

Exercise Verifications.1

Write a contract that stores an integer, and other information you may need.

Anyone should be able to add to this counter, a positive value that is lower than 10.

The same person should not be able to add twice in a row. Someone else has to call it in between.

Note that you will need to store an address in the contract. For now, initialize it with the address of the owner of the contract. We will later see a better approach.

Then add two entry points, one to substract a value, and one to reset the value to 0.

Only the owner of the contract may call these entry points.

## 6 Archetype verification

Archetype Video on verifications: https://www.youtube.com/watch?v=YO-T5tsrjuM

Exercise Verifications.1

Write a contract that stores an integer, and other information you may need.

Anyone should be able to add to this counter, a positive value that is lower than 10.

The same person should not be able to add twice in a row. Someone else has to call it in between.

Note that you will need to store an address in the contract. For now, initialize it with the address of the owner of the contract. We will later see a better approach.

Then add two entry points, one to substract a value, and one to reset the value to 0.

Only the owner of the contract may call these entry points.

## 6 Smarty verification

Video on verifications in SmartPy: https://youtu.be/u98Z6oGgwOQ

Video on using multiple values: https://youtu.be/8316qAQqCs8

1) Add verifications to the endless wall contract from the previous exercise.

People may only add strings with a length between 3 and 30 characters included.

2) Add tests that make sure that your contract does this well

To obtain the length of a string, use: sp.len("a string")

3) Modify the contract wall so that it also keeps track of the number of calls

4) Modify the contract so that users also send their names, between 3 and 15 characters.
Each call should add "[Name]: [Message]". For example "Mathias: Hello"

**Reminders:**

- use assert [condition] to perform a check
- use assert [condition], "[error message"]  to include an error message in the case of a failure
- you may use regular comparison operators: <, >, <=, >=, !=, ==
- you may use and, or, not but also ^ (exclusive or) operators.

**In the test scenario:**

- to check that a call fails when it should: c1.my_entrypoint(params).run(valid = False)
- to check the error message: c1.my_entrypoint(params).run(valid=False, exception="My error")

**When calling an entrypoint from your test scenario:**

- if the entrypoint has a single parameter, pass only the value: contract.entryPoint(value)
- if there are multiple parameters, pass their names: contract.entryPoint(name1 = v1, name2 = v2)

## 6 Archetype advanced testing

Archetype Video on Advanced tests: https://www.youtube.com/watch?v=I6EDTsrcifw

**Remember**

When you create test scenarios, your goal is not only to create scenarios where you make valid calls and check that everything works well, but also to create scenarios that check that invalid calls do fail as they should.

**Exercise Testing.1**

Add tests to check that the contract from the previous exercise (verifications), works well.

**For example:**

- check that the same person can’t increment twice in a row
- check that only the owner may reset the counter

All potential errors should be tested

## 7 JSligo advanced testing

JSLigo Video on Advanced tests: https://youtube.com/watch?v=mFiXNYS-Y_g

Remember

When you create test scenarios, your goal is not only to create scenarios where you make valid calls and check that everything works well, but also to create scenarios that check that invalid calls do fail as they should.

Exercise Testing.1

Add tests to check that the contract from the previous exercise (verifications), works well.

**For example:**

- check that the same person can’t increment twice in a row
- check that only the owner may reset the counter

All potential errors should be tested

## 7a Smarty address

Video on addresses in SmartPy: https://youtu.be/Akch_06Y2D4

Modify your endlesswall contract from the previous exercise, so that the same user can't add text twice in a row.

In other words, between two calls from a given user, at least one other user must have added text.

**Reminders:**

- we introduced a new type sp.address for addresses of users (implicit accounts) and contracts (originated accounts)
- addresses of implicit accounts start with "tz", while those of originated accounts start with "KT"
- to hard-code address, we can use address literals: admin = sp.address("tz1abwc....")
- the address of the direct caller of a contract can be obtained using sp.sender
- we can simply compare addresses: assert sp.sender == admin

**In the test scenario:**

- we can create new accounts: alice = sp.test_account("Alice")
- then obtain their address: alice.address
- when calling a contract, we can specify who is making the call: c1.add(5).run(sender = alice)
- remember how to check that the contract fails: c1.add(10).run(sender = bob, valid = False)

## 7a Smarty NFTs

Video on NFTs: https://youtu.be/cdBG_RZU05Y

Using what you have learned so far, create your own single NFT contract in SmartPy.

**Remember that an NFT:**

- Is Uniquely identifiable
- Contains some information: metadata
- Has an owner
- Can be transferred

**Reminders:**

- A smart contract and its storage can be the NFT
- Every contract is unique and identified by its address
- The contract can store the owner of the NFT
- It can store the metadata, for example a string “[your name]’s first NFT”
- To make it transferable, your contract needs an entrypoint that:
    - Updates the address of the owner
    - Only lets the current owner initiate the transfer

## 8 JSligo transactions

JSLigo Video on transactions: https://youtube.com/watch?v=Lc2mRWzrYz8

**Remember**

On Tezos, when you call an entry point of a contract, you are sending tez to that contract (it could be 0 tez). If the call succeeds, your tez are transferred. But if the contract, or any of the transactions it produces, directly or indirectly, fail, everything is cancelled and your tez are never transferred.

**Exercise Transactions.1**

Write a Smart Contract that has a collect entry point, that allows its owner to withdraw an amount of tez from the balance of the contract.

The owner has to wait at least 2 minutes between each withdrawal.

The owner should not withdraw, each time, more than a maximum amount, that we set in the storage during the origination.

Add a deposit entry point that lets anyone deposit some Tez.

**Exercise Transactions.2**

Change the  deposit entry point so that allows anyone to deposit at least 100 tez. When doing so, the caller may change the withdrawal limit. The caller may not reduce the withdrawal limit below 1 though.

**Exercise Transactions.3**

Instead of a maximum value that we can withdraw. Make it so that the owner may only withdraw up to a certain percentage of the balance. This percentage should be set in the storage, during the origination of the contract.

The deposit entry point should allow users to change this percentage, but not reduce it below 1%.

## 8 Archetype transactions

Archetype Video on transactions: https://www.youtube.com/watch?v=GX537VHF3Gg

**Important note**

On Tezos, when you call an entry point of a contract, you are sending tez to that contract (it could be 0 tez). If the call succeeds, your tez are transferred. But if the contract, or any of the transactions it produces, directly or indirectly, fail, everything is cancelled and your tez are never transferred.

**Exercise Transactions.1**

Write a Smart Contract that has a collect entry point, that allows its owner to withdraw an amount of tez from the balance of the contract.

The owner has to wait at least 2 minutes between each withdrawal.

The owner should not withdraw, each time, more than a maximum amount, that we set in the storage during the origination.

Add a deposit entry point that lets anyone deposit some Tez.

**Exercise Transactions.2**

Change the  deposit entry point so that allows anyone to deposit at least 100 tez. When doing so, the caller may change the withdrawal limit. The caller may not reduce the withdrawal limit below 1 though.

**Exercise Transactions.3**

Instead of a maximum value that we can withdraw. Make it so that the owner may only withdraw up to a certain percentage of the balance. This percentage should be set in the storage, during the origination of the contract.

The deposit entry point should allow users to change this percentage, but not reduce it below 1%.

## 8 Smarty transactions

Video on transactions in SmartPy: https://youtu.be/Fc501BUfpUc

Change your NFT contract so that the owner can set a price, and other users can purchase it for that price.

You will need two new entrypoints: 

- set_price(newPrice), to let the seller set or update the sale price
- buy(), to be called by the buyer. It will need to:
    - Check that the buyer transferred the correct amount, using sp.amount
    - Send that amount to the seller’s address, from the balance of the contract
    - Transfer ownership of the NFT to the buyer

**Reminders:**

- In the scenario, when calling a contract, we may send some tez to it: testContract.myEntryPoint.run(sender = alice, amount = sp.tez(5))
- Entrypoints can check the amount transferred: assert sp.amount >= sp.tez(5)
- The amount is immediately added to the balance of the contract
- The entrypoint can check the new balance: assert sp.balance >= sp.tez(10)
- A contract can send some tez to an address: sp.send(userAddress, sp.tez(10))
- Such transactions are not immediate, they are performed after the entrypoint code is executed
- If something fails, everything is canceled:
    - If the balance is insufficient
    - If the destination address is a contract and rejects the transfer
- In the scenario, we can check the contracts balance:
```
testContract.myEntryPoint.run(sender = alice, amount = sp.tez(5))
balanceAfter = testContract.balance
```

- Mutez are stored as 64 bits unsigned value and have an upper limit. Reaching it causes a failure

## 8 Smarty options

Video on options in SmartPy: https://youtu.be/lygGT5WyrcA

Note that the syntax sp.unwrap_some(myOption) is incorrect, it should now be myOption.unwrap_some()

Modify the NFT for sale contract so that the NFT is not always on sale

Use an option so that the NFT is not always on sale:

- Use setPrice() with None if you don’t want it to be on sale
- Set the price to None right after the sale, so that it can’t be bought again immediately

**Reminders:**

- You can use sp.some(value) or None to create an option
- Two options can be compared for equality:assert myOption == sp.Some(42) or assert myOption != None
- You can extract the value by unwrapping the option:v = myOption.unwrap_some()
- Any other operation, such as adding two values, requires unwrapping the options first
- You can create options on most types, including complex ones (that we will see later)
- Only use options when they really help or when there is no choice. They may unnecessarily complexify the code.
- Use nobody = sp.address("KT18amZmM5W7qDWVt2pH6uj7sCEd3kbzLrHT") if you need an invalid address
- When calling an emtrypoint from a test, if you want to pass None, you need to use sp.none. This will most likely change soon, so that you can use None there as well

## 8 Smarty timestamps

Video on timestamps in SmartPy: https://youtu.be/nhqELUUxf5k

Change your NFT contract so that it can't be sold again less than 5 days since it was last bought.

**Reminders:**

- The current time is not available from a contract, as every node needs to get the same result
- Instead, a contract can access the time of the current block
- This time is predictable based on information from the previous block
- Timestamps are a number of seconds since 01/01/1970, and can be infinitely negative or positive
- Timestamps can be created in three ways:
    - Using a number of seconds since 01/01/1970: sp.timestamp(42000)
    - Using a list of parameters: sp.timestamp_from_utc(year, month, day, h, m, s)
    - Getting the timestamp of the current block: sp.now
- You can add time to a timestamp: d = sp.add_seconds(a, 42)
- Compare two timestamps: assert sp.now <= deadline, "too late"
- Compute the difference between two timestamps: assert sp.now - lastCall > 60, "too soon"
- When testing, time doesn't pass automatically, and is 0 by default. You have to specify it in your calls:myContract.myEntryPoint(param).run(now = sp.timestamp(4000))

## 8 Smarty aritmetics

Video on arithmetics in SmartPy: https://youtu.be/tmtn9zuD1KY

Change your NFTForSale contract, so that the price is automatically set: it should increase by 10% after every sale.

If we start our NFT with a price of 1 tez, it will be worth:

- 1.10 tez after one sale
- 2.59 tez after 10 sales
- …
- 13780 tez after 100 sales


**Reminders:**

- Arithmetic operators such as `-`, `+`, `*`, / (integer division), can be used for two values of the same type
- For values of different types or more, use sp.mod(a, b), sp.add(a,b), sp.mul(a,b), sp.ediv(a,b)
- Return types:
    - Addition, multiplication and integer division return nat if both operands are nat, and int if one operand is an int
    - Substraction and negation return an int whether operands are int or nat
    - Modulo always returns a nat
    - sp.ediv(a,b) returns an option on a pair of values (q,r): the quotient and remainder

**For mutez:**

- Addition and substraction of mutez gives a result of type sp.mutez
- Multiplying mutez with nat (or vice-versa) gives a result of type sp.mutez
- Additions and multiplications of mutez fail in case of overflows

**Pairs:**
- Create a pair using (-42, "example"), which is of type sp.pair[sp.int, sp.string]
- Extract the first or second component of a pair: sp.fst(pair) or sp.snd(pair)
- Extract the components in two variables (or more for a tuple) : (a, b) = (42, "abc")

**Type conversions:**

- mutez to nat: utils.mutez_to_nat(n)
- nat to mutez: utils.nat_to_mutez(n) or utils.nat_to_tez(n)
- nat to int: sp.to_int(nat)
- int to nat: sp.as_nat(int)

**Computing percentages**

- sp.split_tokens(tezAmount, quantity, totalQuantity) returns tezAmount * quantity / totalQuantity

## 9 JSligo maps records

JSLigo Video on Maps and Records: https://youtube.com/watch?v=v-gmr2_rJYI

**Exercise Maps.1**

**Step 1: add some tests**

Create a test scenario for  the visitors example contract.

In particular, test:

- the registration of a new user
- multiple visits from that user
- check that visits are counted correctly

**Step 2**

Modify the contract so that:

- The address of the caller is used, rather than a login, to identify users.
- Make users pay 5 tez for the first visit, and 3 tez for the next ones
- Enforce a delay of a minimum of 10 days between two visits of the same user.

Test these changes

## 9 Archetype assets

Archetype Video on Assets and Records: https://www.youtube.com/watch?v=FdLvNP8LoqM

**Important notes**

1. Since the video, some function names have changed:
- addupdate becomes add_update
- removeif becomes remove_if

2. The correct syntax for adding an entry to an asset is:
 visitor.add({ login = "john284"; name = "john" });

The video shows visitor.add("john284", { name = "john" });  but this is the syntax to use for addupdate, not add.


**Exercise Maps.1**

**Step 1: add some tests**

Create a test scenario for  the visitors example contract.

In particular, test:
- the registration of a new user
- multiple visits from that user
- check that visits are counted correctly

**Step 2**

Modify the contract so that:

- The address of the caller is used, rather than a login, to identify users.
- Make users pay 5 tez for the first visit, and 3 tez for the next ones
- Enforce a delay of a minimum of 10 days between two visits of the same user.

Test these changes

## 9 Smarty maps records

Video on maps and records in SmartPy: https://youtu.be/hcfj77JB3Sg

Add a ledger to this contract to fix the flaw:

```python=
import smartpy as sp

@sp.module
def main():

    class MultipleNftSingleContract(sp.Contract):
        def __init__(self, owner):
            self.data.owner = owner
            self.data.next_id = 1
            self.data.tokens = sp.big_map ({})
    
        @sp.entrypoint
        def buy(self, token_id):
            assert self.data.tokens.contains(token_id)
            token = self.data.tokens[token_id]
            assert sp.amount == token.price
            author_fee = sp.split_tokens(token.price, 5, 100)
            sp.send(token.owner, sp.amount - author_fee)
            sp.send(token.author, author_fee)
            token.owner = sp.sender
            token.price += sp.split_tokens(token.price, 10, 100)
    
        @sp.entrypoint
        def mint(self, metadata, price):
            self.data.tokens[self.data.next_id] = sp.record(metadata = metadata, price = price, owner = sp.sender, author = sp.sender)
            self.data.next_id += 1

@sp.add_test(name='Test One')
def test():
    author = sp.test_account('author').address
    alice = sp.test_account('alice').address
    bob = sp.test_account('bob').address
    eve = sp.test_account('eve').address
    c1 = main.MultipleNftSingleContract(alice)
    scenario = sp.test_scenario(main)
    scenario += c1
    c1.mint(metadata='second contract', price=sp.tez(2)).run(sender=author)
    c1.buy(1).run(sender=bob, amount=sp.tez(2))
    scenario.verify(c1.balance == sp.tez(0))
```

**Reminders:**

Records

- Creating a record: aRecord = sp.record(field1 = 1, field2 = "A string")
- Accessing a field: v = aRecord.field1
- Creating a record type: sp.record(field1 = sp.nat, field2 = sp.string)
- Type abbreviations, in the main() module but outside of a contract: tRecord : type = sp.record(field1 = sp.nat, field2 = sp.string)

**Maps:**

- Creating a map with some data: my_map = {0 : "aa", 1 : "bb" }
- Empty map : my_map = {}
- Create an empty map but specify the type: my_map = sp.cast({}, sp.map[sp.int, sp.string])
- Adding/updating entries: my_map[0] = "cc"
- Accessing entry value: v = my_map[1]
- Deleting entries: del my_map[1]
- Check the existence: my_map.contains(1)
- Getting the size: sp.len(my_map)
- Getting list of all entries: my_map.items() returns lists of records: [{ key: 1, value: "aa" }, { key: 2, value: "bb" }]
- Getting list of all keys: my_map.keys()
- Getting list of all values: my_map.values()

**Storage and gas cost issues:**

- the storage is serialized/deserialized between calls. This consumes CPU
- We estimate the amount of CPU time consumed using Gas
- Calling a transaction implies paying for this gas as part of the fee for the baker
- There is a limit to how much gas can be consumed in a single transaction
- A contract can be stuck for ever if we exceed this limit
- Some types have unlimited sizes: int, nat, string, timestamps, maps


**Big_maps:**
- entries in a big map are serialized/deserialized on-demand
- the syntax is the same except using sp.big_map instead of sp.map, and sp.big_map({}) to create an empty one
- the length, list of keys, items or values are not available for big_maps

## 10 Michelson

Video on Michelson: https://youtube.com/watch?v=eUaMUk6MGr0

Warning: please note that in the video, a and b are switched in the example, at minute 3:45 and after. Sorry about that.

Michelson Cheat sheet: https://docs.google.com/document/d/1D4wZNVKec2kBWs9c-AKLlePE_dq9dwnci_vbIcUJu1Y/edit?usp=sharing

A few things to keep in mind (also presented with illustrations at the bottom of the cheat-sheet):

- if when you open a .tz file, you don't see the extension on the right side, that shows you the type of each instruction when you click on it (as shown in the video), you may need to reload the page. It sometimes happens.
- if everything is underlined in red and you simply have "typecheck error", this means the type of what you have in the stack at the end is incorrect. This happens a lot while you change your program, and a good way to avoid this is to add a FAIL instruction at the very end. . This fixes the typecheck error, which makes it much easier to figure out what the issue is.
- the debugger changed since the video, and the syntax to use when passing parameters is now: { 1 ; 10 } instead of (1, 10)
- when you debug your program with the latest version of the debugger, "Cell 0" is the bottom of the stack, then if you have X items on the stack, Cell N-1 is the top of the stack. I the code however, we always refer to elements relative to the top, for example DIG 2 means fetching an element 2 cells from the top, and bringing it to the top.
- if you are debugging your program, change your program, and keep debugging, it's the old version of your program that is still running. This can be really confusing as the debugging will do things that may have nothing to do with what is highlighted in your file, so make sure you stop the debugging of your program before you make changes.

**Exercise Michelson.1**

Write a Michelson Smart Contrat that takes a pair of integers (a,b) as parameter, and replaces its storage with the value of this expression:

```python=
a * (2b + 3a)
```