diff --git a/README.md b/README.md index a75256b..53f0be1 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ serverless mern Tezos Academy is a fun interactive tutorial develloped by OCTO Technology on how to code smart contracts for Tezos. You are about to create a spaceship battle smart contract!

- By default, Tezos smart contracts are written in Michelson, but it is an hard to learn low level formal language. That is why we decide for this tutorial to use PascaLIGO instead. The syntax is high level, close to Pascal and tranpiles to Michelson.

+ By default, Tezos smart contracts are written in Michelson, but it is an hard to learn low level formal language. That is why we decide for this tutorial to use PascaLIGO instead. The syntax is high level, close to Pascal and transpiles to Michelson.

In this tutorial, you are going to build a "Ship Factory" to build an army of spaceships, then we will add more and more functionalities as you progress through the tutorial, such as going into space battles! diff --git a/src/Chapter/Chapter.view.tsx b/src/Chapter/Chapter.view.tsx index e913554..daef0db 100644 --- a/src/Chapter/Chapter.view.tsx +++ b/src/Chapter/Chapter.view.tsx @@ -38,7 +38,7 @@ const MonacoEditor = ({ proposedSolution, proposedSolutionCallback }: any) => { return (
{ return (
OCTO Technology on how to code smart contracts for Tezos. You are about to create spaceship battles smart contracts! -By default, Tezos smart contracts are written in Michelson, but it is an hard to learn low level formal language. For this tutorial, we will use PascaLIGO instead. The syntax is high level, close to Pascal and tranpiles to Michelson. +By default, Tezos smart contracts are written in Michelson, but it is an hard to learn low level formal language. For this tutorial, we will use PascaLIGO instead. The syntax is high level, close to Pascal and transpiles to Michelson. ## Objectives diff --git a/src/Chapters/ChapterAbout/ChapterAbout.style.tsx b/src/Chapters/ChapterAbout/ChapterAbout.style.tsx index 45f6253..4ea539e 100644 --- a/src/Chapters/ChapterAbout/ChapterAbout.style.tsx +++ b/src/Chapters/ChapterAbout/ChapterAbout.style.tsx @@ -16,7 +16,7 @@ export const ChapterStyled = styled.div` export const ChapterGrid = styled.div` display: grid; - grid-template-rows: 440px auto; + grid-template-rows: 500px auto; grid-gap: 20px; overflow-y: scroll; @@ -102,7 +102,7 @@ export const Button = styled.div` position: relative; display: inline-block; cursor: pointer; - margin: 20px auto; + margin: 20px auto 10px auto; `; export const ButtonBorder = styled.div` diff --git a/src/Chapters/ChapterConditionals/course.md b/src/Chapters/ChapterConditionals/course.md index 7bb4716..6c28bbb 100644 --- a/src/Chapters/ChapterConditionals/course.md +++ b/src/Chapters/ChapterConditionals/course.md @@ -33,6 +33,10 @@ const b : tez = 10mutez const c : bool = (a = b) // false ``` +⚠️ Notice that equality is checked with a single _=_ and not two like many languages. + +⚠️ Also notice the use of _=/=_ for the inequality operator. + ## Conditionals Conditional logic enables forking the control flow depending on the state. @@ -55,10 +59,10 @@ else skip; ## Your mission -We want to add contional so that we change the engine attribute to 1 only if it is equal to 0. +We want to conditionally change the engine attribute (third number) to 1 only if it is equal to 0. 1- Refactor *modified\_ship* as a variable equal to *my\_ship* -2- Then define a condition _if_ the engine attribute equal 0. Don't forget the attribates are defined as strings. +2- Then define a condition _if_ the engine attribute equal 0. Don't forget the attributes are defined as strings. 3- If the condition is met, change *modified\_ship* to it new value. Otherwise, _skip_ the instructions. diff --git a/src/Chapters/ChapterFunctions/course.md b/src/Chapters/ChapterFunctions/course.md index 2390d91..8edbfc5 100644 --- a/src/Chapters/ChapterFunctions/course.md +++ b/src/Chapters/ChapterFunctions/course.md @@ -2,7 +2,7 @@ Captain, why are you trying to change the part yourself? Just write a function on the terminal and send it to a droid. -LIGO functions are the basic building block of contracts. Each entrypoint of a contract is a function and each smart contract must have at least one function named _main_ that dispatches controls to the other functions. +LIGO functions are the basic building block of contracts. Each entrypoint of a contract is a function and each smart contract must have at least one function named _main_ that dispatches the control flow to other functions. When calling a function, LIGO makes a copy of the arguments but also the environment variables. Therefore any modification to these will not be reflected outside the scope of the function and will be lost if not explicitly returned by the function. diff --git a/src/Chapters/ChapterInteractions/course.md b/src/Chapters/ChapterInteractions/course.md index 18c549b..c9a1bc8 100644 --- a/src/Chapters/ChapterInteractions/course.md +++ b/src/Chapters/ChapterInteractions/course.md @@ -6,34 +6,32 @@ A contract can invoke another by emiting a transaction operation at the end of an entrypoint. -## Syntax +## Transactions -The keyword _operation_ is a predefined type which model transaction (contract invocation). - -The keyword _transaction_ is predefined function which generates an _operation_ from following parameters: - -- target contract parameter (entrypoint call to execute on the target contract) -- amount to transfer -- the target contract interface (which describes possible entrypoints of targeted contract) - - _transaction_ function follows the syntax: +We have already seen the _Tezos.transaction_ in chapter 17 in order to send money to an address. It is also possible to use _Tezos.transaction_ to call an entrypoint from another contract. In that case, we store the transaction in a type _operation_ which is a predefined type representing a contract invocation. ``` -const : operation = Tezos.transaction(, , ); +const : operation = Tezos.transaction (, , ); ``` -The contract interface of an already deployed contract can be retrieved with the *get\_contract* function. It takes the address of the target contract and returns a contract interface. The _contract_ type is a template type which dpends on a the type of target contract parameter. +where : + +- _parameter_ is the entrypoint to call on the target contract, +- _mutez_ is the amount to transfer, +- _contract_ is the contract we want to interact with. + +To get the contract we want to call and its entry points, we can use : ``` -const : contract() = Tezos.get_contract_opt(); +Tezos.get_contract_opt(
) ``` -Since a contract might be destroyed, the call to *Tezos.get\_contract\_opt* may not find the target contract. For a safer purpose, the function *get\_contract\_opt* is also available to retrieve a contract interface and work as *get\_contract* but returns an option of _contract(parameter)_ +The function take an address and return an optional _contract_ (remember to use _option_). When no contract is found or the contract doesn't match the type, _None_ is returned. ## Example The following example shows how a contract can invoke another by emiting a transaction operation at the end of an entrypoint. -In our case, we have a counter.ligo contract that accepts an action of type parameter, and we have a proxy.ligo contract that accepts the same parameter type, and forwards the call to the deployed counter contract. +In our case, we have a _counter.ligo_ contract that accepts an action of type _parameter_, and we have a _proxy.ligo_ contract that accepts the same parameter type, and forwards the call to the deployed counter contract. ``` // counter.ligo @@ -59,28 +57,27 @@ function main (const action : parameter; const store : storage) : return is ``` // proxy.ligo +type storage is unit + type parameter is Increment of nat | Decrement of nat | Reset -type storage is unit - type return is list (operation) * storage -const dest : address = ("KT19wgxcuXG9VH4Af5Tpm1vqEKdaMFpznXT3" : address) +const dest : address = ("KT19wgxcuXG9VH4Af5Tpm1vqEKdaMFpznXT3" : address) // Deployment address of counter.ligo function proxy (const action : parameter; const store : storage): return is block { const counter : contract (parameter) = - case (Tezos.get_contract_opt (dest) : option (contract (parameter))) of + case (Tezos.get_contract_opt(dest) : option (contract (parameter))) of Some (contract) -> contract | None -> (failwith ("Contract not found.") : contract (parameter)) end; - const mock_param : parameter = Increment (5n); - const op : operation = Tezos.transaction (action, 0tez, counter); - const ops : list (operation) = list [op] - } with (ops, store) + const op : operation = Tezos.transaction (action, 0tez, counter); // E.g. with action = Increment (5n) + const operations : list (operation) = list [op] + } with (operations, store) ``` Notice that : @@ -89,38 +86,28 @@ Notice that : - the _proxy_ function returns a list of operation containing the newly created transaction. - the _parameter_ type (counter parameter) has also been defined in proxy contract. The calling contract must know the parameter type of called contract. -## Polymorphism - -When sending transactions between contracts, each contract must know the target contract interface and the parameter type of the target contract. This is done basicaly by separating type definition and function implementation and by using inclusion. But a problem arises when creating a new contract which must communicate way and back (two-way communication) with an already deployed contract. The deployed contract cannot know the signature of a contract not yet created! - -Hopefully a solution exists to this problem of polymorphism, it is *Tezos.get\_entrypoint\_opt* function. - -Let's consider two contracts _A_ and _B_. Contract _A_ ask some information from contract _B_ and they communicate between each other with transactions. -A sends a request to B, (it means _A_ calls an entrypoint of _B_, so contract _A_ includes type definition of _B_) -B receives the request, process the request and sends an response back to _A_ (it means _B_ calls an entrypoint of _A_, , so contract _B_ includes type definition of _A_) -Once they are deployed, we cannot change their includes. - -Now let's consider a third smart contract _C_ which will communicate with _B_. (Like _A_) -Since we can't change _B_ (already deployed) , then _C_ must have same definition of _A_ to be able to receive transactions from _B_. - -The problem is coming from the fact that _B_ must know the whole definition of _A_ parameter but it actually only needs one entrypoint used for the transaction. If _C_ implements the same entrypoint than _A_ (for receiving a message from _B_) then transaction will match the entrypoint and problems solved ! - -For this purpose, the predefined function *Tezos.get\_entrypoint\_opt* can be used to retrieve the definition of a single entrypoint (from the whole variant). +## Your mission -The predefined function *Tezos.get\_entrypoint\_opt* can be used in replacement of the *Tezos.get\_contract\_opt* function to retrieve contract interface but for only one entrypoint. It takes the requested entrypoint as parameter (with a special michelson syntax) and the address of the contract. +1- Consider each of our weapons is managed by a smart contract : ``` -const : contract() = Tezos.get_entrypoint_opt(, ); -``` - - *entrypoint\_name* is a double-quoted string with first character is % followed by the name of the entrypoint (and its first letter must not be capitalized) exemple: for an entrypoint FooBar the corresponding *entrypoint\_name* is "%fooBar" +// weapon.ligo +type storage is int -## Your mission +type parameter is + Fire of int +| Stop -1- Consider the following smart contract : +type return is list (operation) * storage +function main (const action : parameter; const store : storage) : return is + ((nil : list (operation)), + case action of + Fire (n) -> n + | Stop -> 0 + end) ``` -``` +2- Consider the contract in the editor. Notice the addresses of each weapon, and that the _orders_ function fetch the corresponding contracts. Your job is now to define the list of operations to send to the weapons. For this, start by creating _operations_ a list of type _operation_. -2- +3- Send a _Fire(5)_ transaction to the *right\_laser* contract, then _Stop_. Send a _Fire(5)_ transaction to the *left\_laser* contract, then _Stop_. diff --git a/src/Chapters/ChapterInteractions/exercise.ligo b/src/Chapters/ChapterInteractions/exercise.ligo index 66125c7..8b6986f 100644 --- a/src/Chapters/ChapterInteractions/exercise.ligo +++ b/src/Chapters/ChapterInteractions/exercise.ligo @@ -1 +1,27 @@ -// Type your solution below \ No newline at end of file +type storage is unit + +type parameter is + Fire of int +| Stop + +type return is list (operation) * storage + +const right_laser_address : address = ("tz1fND4ejogxWN7HB5JKdz119A48Cp2eYKj9" : address) +const left_laser_address : address = ("tz1PVWEWDcuow9R6y5EFwcHbFNoZBZ9RjxaB" : address) + +function orders (const action : parameter; const store : storage): return is + block { + const right_laser : contract (action) = + case (Tezos.get_contract_opt(main_laser_address) : option (contract (parameter))) of + Some (contract) -> contract + | None -> (failwith ("Contract not found.") : contract (parameter)) + end; + const left_laser : contract (action) = + case (Tezos.get_contract_opt(main_laser_address) : option (contract (parameter))) of + Some (contract) -> contract + | None -> (failwith ("Contract not found.") : contract (parameter)) + end; + + // Type your solution below + + } with (operations, store) diff --git a/src/Chapters/ChapterInteractions/solution.ligo b/src/Chapters/ChapterInteractions/solution.ligo index 66125c7..bd870de 100644 --- a/src/Chapters/ChapterInteractions/solution.ligo +++ b/src/Chapters/ChapterInteractions/solution.ligo @@ -1 +1,32 @@ -// Type your solution below \ No newline at end of file +type storage is unit + +type parameter is + Fire of int +| Stop + +type return is list (operation) * storage + +const right_laser_address : address = ("tz1fND4ejogxWN7HB5JKdz119A48Cp2eYKj9" : address) +const left_laser_address : address = ("tz1PVWEWDcuow9R6y5EFwcHbFNoZBZ9RjxaB" : address) + +function orders (const action : parameter; const store : storage): return is + block { + const right_laser : contract (action) = + case (Tezos.get_contract_opt(main_laser_address) : option (contract (parameter))) of + Some (contract) -> contract + | None -> (failwith ("Contract not found.") : contract (parameter)) + end; + const left_laser : contract (action) = + case (Tezos.get_contract_opt(main_laser_address) : option (contract (parameter))) of + Some (contract) -> contract + | None -> (failwith ("Contract not found.") : contract (parameter)) + end; + + // Type your solution below + const operations : list (operation) = list [ + Tezos.transaction (Fire(5), 0tez, right_laser); + Tezos.transaction (Stop, 0tez, right_laser); + Tezos.transaction (Fire(5), 0tez, left_laser); + Tezos.transaction (Stop, 0tez, left_laser); + ] + } with (operations, store) diff --git a/src/Chapters/ChapterLoops/course.md b/src/Chapters/ChapterLoops/course.md index 9afd32f..96edd71 100644 --- a/src/Chapters/ChapterLoops/course.md +++ b/src/Chapters/ChapterLoops/course.md @@ -14,7 +14,9 @@ while block { } ``` -⚠️ If the while condition is never met, the block will will repeatedly be evaluated until the contract run out of gas or fails. +⚠️ If the while condition is never met, the block will repeatedly be evaluated until the contract run out of gas or fails. + +ℹ️ About gas : The smart contracts interpreter uses the concept of gas. Each low-level instruction evaluation burns an amount of gas which is crafted to be proportional to the actual execution time and if an execution exceeds its allowed gas consumption, it is stopped immediately and the effects of the execution are rolled back. The transaction is still included in the block and the fees are taken, to prevent the nodes from being spammed with failing transactions. In Tezos, the economic protocol sets the gas limit per block and for each transaction, and the emitter of the transaction also set an upper bound to the gas consumption for its transaction. The economic protocol does not require the transaction fee to be proportional to the gas upper bound, however the default strategy of the baking software (that forges blocks) provided with Tezos current implementation does require it. ## For Loops diff --git a/src/Chapters/ChapterMainFunction/course.md b/src/Chapters/ChapterMainFunction/course.md index a8a6db2..b524ea6 100644 --- a/src/Chapters/ChapterMainFunction/course.md +++ b/src/Chapters/ChapterMainFunction/course.md @@ -2,6 +2,8 @@ God damn it rookie! What are you still doing at the space port? Take off already and go shoot some alien!! +Smart contracts are small programs that are stored and executed on the blockchain. They allow people to cooperate and exchange tokens without requiring them to trust one another. + A LIGO contract is made of a series of constant and function declarations. Only functions having a special type can be called when the contract is activated: we call them main functions. A main function takes two parameters, the contract parameter and the on-chain storage, and returns a pair made of a list of operations and a (new) storage. When the contract is originated, the initial value of the storage is provided. When a main function is later called, only the parameter is provided, but the type of a main function contains both. @@ -37,27 +39,27 @@ The parameter of the contract is then a variant type, and, depending on the cons In the following example, the storage contains a counter of type nat and a name of type string. Depending on the parameter of the contract, either the counter or the name is updated. ``` -type Action is +type parameter is Action_A of string | Action_B of string -type Storage is record [ +type storage is record [ stored_string_A : string; stored_string_B : string ] type return is list (operation) * storage -function entry_A (const input_string : string; const storage : Storage) : return is - ((nil : list (operation)), storage with record [stored_string_A = input_string]) +function entry_A (const input_string : string; const store : storage) : return is + ((nil : list (operation)), store with record [stored_string_A = input_string]) -function entry_B (const input_string : string; const storage : Storage) : return is - ((nil : list (operation)), storage with record [stored_string_B = input_string]) +function entry_B (const input_string : string; const store : storage) : return is + ((nil : list (operation)), store with record [stored_string_B = input_string]) -function main (const action : Action; const storage : Storage): return is +function main (const action : parameter; const store : storage): return is case action of - Action_A (input_string) -> entry_A (input_string, storage) - | Action_B (input_string) -> entry_B (input_string, storage) + Action_A (input_string) -> entry_A (input_string, store) + | Action_B (input_string) -> entry_B (input_string, store) end ``` @@ -65,9 +67,9 @@ function main (const action : Action; const storage : Storage): return is ## Your mission -1- The editor contains an example of main function with two functions. In the Action variant, replace *Action\_A* and *Action\_B* with our actions *Set\_ship\_code* and *Go\_to* +1- The editor contains an example of main function with two functions. In the parameter variant, replace *Action\_A* and *Action\_B* with our actions *Set\_ship\_code* and *Go\_to* -2- In the Storage record, replace *stored\_string\_A* and *stored\_string\_B* with the strings we want to store in the contract: *ship\_code* and *destination* +2- In the storage record, replace *stored\_string\_A* and *stored\_string\_B* with the strings we want to store in the contract: *ship\_code* and *destination* 3- Modify the name of our entrypoints *entry\_A* and *entry\_B* to *set\_ship\_code* and *go\_to* diff --git a/src/Chapters/ChapterMainFunction/exercise.ligo b/src/Chapters/ChapterMainFunction/exercise.ligo index 8dc9bbf..7c1a5eb 100644 --- a/src/Chapters/ChapterMainFunction/exercise.ligo +++ b/src/Chapters/ChapterMainFunction/exercise.ligo @@ -1,5 +1,5 @@ // Modify the code below -type action is +type parameter is Action_A of string | Action_B of string @@ -16,8 +16,8 @@ function entry_A (const input_string : string; const store : storage) : return i function entry_B (const input_string : string; const store : storage) : return is ((nil : list (operation)), store with record [stored_string_B = input_string]) -function main (const input_action : action; const store : storage): return is - case input_action of +function main (const action : parameter; const store : storage): return is + case action of Action_A (input_string) -> entry_A (input_string, store) | Action_B (input_string) -> entry_B (input_string, store) end diff --git a/src/Chapters/ChapterMainFunction/solution.ligo b/src/Chapters/ChapterMainFunction/solution.ligo index 16597ed..b402d14 100644 --- a/src/Chapters/ChapterMainFunction/solution.ligo +++ b/src/Chapters/ChapterMainFunction/solution.ligo @@ -1,5 +1,5 @@ // Modify the code below -type action is +type parameter is Set_ship_code of string | Go_to of string @@ -16,8 +16,8 @@ function set_ship_code (const input_string : string; const store : storage) : re function go_to (const input_string : string; const store : storage) : return is ((nil : list (operation)), store with record [destination = input_string]) -function main (const input_action : action; const store : storage): return is - case input_action of +function main (const action : parameter; const store : storage): return is + case action of Set_ship_code (input_string) -> set_ship_code (input_string, store) | Go_to (input_string) -> go_to (input_string, store) end diff --git a/src/Chapters/ChapterMath/course.md b/src/Chapters/ChapterMath/course.md index 8236077..995871d 100644 --- a/src/Chapters/ChapterMath/course.md +++ b/src/Chapters/ChapterMath/course.md @@ -8,7 +8,7 @@ LIGO offers three built-in numerical types: - _nat_ are natural numbers (integral numbers greater than or equal to zero). They are follwed by the suffix _n_ such as 3n, 12n and 0n for the natural zero. -- _tez_ are units of measure of Tezos tokens. They can be decinmals and are followed by _tez_ or _tz_ such as 3tz or 12.4tez. You can also type units of millionth of tez, using the suffix _mutez_ after a natural literal, such as 10000mutez or 0mutez. +- _tez_ are units of measure of Tezos tokens. They can be decimals and are followed by _tez_ or _tz_ such as 3tz or 12.4tez. You can also type units of millionth of tez, using the suffix _mutez_ after a natural literal, such as 10000mutez or 0mutez. ⚠️ Notice there are no floating point types in LIGO as they are not determinist in hardware modules. diff --git a/src/Chapters/ChapterMath/solution.ligo b/src/Chapters/ChapterMath/solution.ligo index 69fb1c7..6f4d1bf 100644 --- a/src/Chapters/ChapterMath/solution.ligo +++ b/src/Chapters/ChapterMath/solution.ligo @@ -1,4 +1,4 @@ // Type your solution below -const required_energy : int = 1210; -const energy_per_battery_pack : int = 160; +const required_energy : int = 1210 +const energy_per_battery_pack : int = 160 const required_battery_packs : int = required_energy / energy_per_battery_pack + 1 \ No newline at end of file diff --git a/src/Chapters/ChapterOption/course.md b/src/Chapters/ChapterOption/course.md index 4c6146e..b0dca32 100644 --- a/src/Chapters/ChapterOption/course.md +++ b/src/Chapters/ChapterOption/course.md @@ -57,4 +57,4 @@ end 1- Notice the _weapons_ mapping which maps the name of each weapon to its corresponding input of power. We want to increase the power of the _Main Laser_ but mapping returns optional results as they might not be found in the mapping. Define the constant *main\_laser\_power* as an optional int from selecting _"Main Laser"_ from the _weapons_ mapping. - 2- Writte a pattern matching for *main\_laser\_power*. If it exixts, increase the power of the _"Main Laser"_ by 1. If it does not exist in the mapping, fail with _"Weapon not found"_ + 2- Writte a pattern matching for *main\_laser\_power*. If it exists, increase the power of the _"Main Laser"_ by 1. If it does not exist in the mapping, fail with _"Weapon not found"_ diff --git a/src/Chapters/ChapterInteractions/central.ligo b/src/Chapters/ChapterPolymorphism/central.ligo similarity index 100% rename from src/Chapters/ChapterInteractions/central.ligo rename to src/Chapters/ChapterPolymorphism/central.ligo diff --git a/src/Chapters/ChapterInteractions/central_types.ligo b/src/Chapters/ChapterPolymorphism/central_types.ligo similarity index 100% rename from src/Chapters/ChapterInteractions/central_types.ligo rename to src/Chapters/ChapterPolymorphism/central_types.ligo diff --git a/src/Chapters/ChapterPolymorphism/course.md b/src/Chapters/ChapterPolymorphism/course.md new file mode 100644 index 0000000..6de752e --- /dev/null +++ b/src/Chapters/ChapterPolymorphism/course.md @@ -0,0 +1,43 @@ +# Chapter 21 : Polymorphism + + + + + +When sending transactions between contracts, each contract must know the target contract interface and the parameter type of the target contract. This is done basicaly by separating type definition and function implementation and by using inclusion. But a problem arises when creating a new contract which must communicate way and back (two-way communication) with an already deployed contract. The deployed contract cannot know the signature of a contract not yet created! + +Hopefully a solution exists to this problem of polymorphism, it is *Tezos.get\_entrypoint\_opt* function. + +Let's consider two contracts _A_ and _B_. Contract _A_ ask some information from contract _B_ and they communicate between each other with transactions. +A sends a request to B, (it means _A_ calls an entrypoint of _B_, so contract _A_ includes type definition of _B_) +B receives the request, process the request and sends an response back to _A_ (it means _B_ calls an entrypoint of _A_, , so contract _B_ includes type definition of _A_) +Once they are deployed, we cannot change their includes. + +Now let's consider a third smart contract _C_ which will communicate with _B_. (Like _A_) +Since we can't change _B_ (already deployed) , then _C_ must have same definition of _A_ to be able to receive transactions from _B_. + +The problem is coming from the fact that _B_ must know the whole definition of _A_ parameter but it actually only needs one entrypoint used for the transaction. If _C_ implements the same entrypoint than _A_ (for receiving a message from _B_) then transaction will match the entrypoint and problems solved ! + +For this purpose, the predefined function *Tezos.get\_entrypoint\_opt* can be used to retrieve the definition of a single entrypoint (from the whole variant). + +The predefined function *Tezos.get\_entrypoint\_opt* can be used in replacement of the *Tezos.get\_contract\_opt* function to retrieve contract interface but for only one entrypoint. It takes the requested entrypoint as parameter (with a special michelson syntax) and the address of the contract. + +``` +const : contract() = Tezos.get_entrypoint_opt(, ); +``` + + *entrypoint\_name* is a double-quoted string with first character is % followed by the name of the entrypoint (and its first letter must not be capitalized) exemple: for an entrypoint FooBar the corresponding *entrypoint\_name* is "%fooBar" + + To get a contract from an address and entrypoint, we can use _Tezos.get_entrypoint_opt(,
)_ + +Entrypoints are written in the form of: _%myEntryPoint_ for the enty point _MyEntryPoint_. Notice we change the case of the first letter. When no contract is found or the contract doesn't match the type, _None_ is returned. Remember to use _option_ for the return type as it is optional. + +## Your mission + +1- Consider the following smart contract : + +``` + +``` + +2- diff --git a/src/Chapters/ChapterPolymorphism/exercise.ligo b/src/Chapters/ChapterPolymorphism/exercise.ligo new file mode 100644 index 0000000..b92e9df --- /dev/null +++ b/src/Chapters/ChapterPolymorphism/exercise.ligo @@ -0,0 +1,10 @@ +function purchase (const purchase_price : tez) : bool is + const ship_address : address = ("tz1TGu6TN5GSez2ndXXeDX6LgUDvLzPLqgYV" : address); + const vendor_address : address = ("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx" : address); + + if Tezos.source =/= ship_address then failwith ("Access denied"); + if Tezos.amount =/= purchase_price then failwith ("Incorrect amount"); + + // Type your solution below + +return True \ No newline at end of file diff --git a/src/Chapters/ChapterPolymorphism/index.ts b/src/Chapters/ChapterPolymorphism/index.ts new file mode 100644 index 0000000..c3a2f03 --- /dev/null +++ b/src/Chapters/ChapterPolymorphism/index.ts @@ -0,0 +1,11 @@ +/* eslint import/no-webpack-loader-syntax: off */ +// @ts-ignore +import course from "!raw-loader!./course.md"; +/* eslint import/no-webpack-loader-syntax: off */ +// @ts-ignore +import exercise from "!raw-loader!./exercise.ligo"; +/* eslint import/no-webpack-loader-syntax: off */ +// @ts-ignore +import solution from "!raw-loader!./solution.ligo"; + +export const dataTransactions = { course, exercise, solution }; diff --git a/src/Chapters/ChapterPolymorphism/solution.ligo b/src/Chapters/ChapterPolymorphism/solution.ligo new file mode 100644 index 0000000..e55420a --- /dev/null +++ b/src/Chapters/ChapterPolymorphism/solution.ligo @@ -0,0 +1,10 @@ +function purchase (const purchase_price : tez) : bool is + const ship_address : address = ("tz1TGu6TN5GSez2ndXXeDX6LgUDvLzPLqgYV" : address); + const vendor_address : address = ("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx" : address); + + if Tezos.source =/= ship_address then failwith ("Access denied"); + if Tezos.amount =/= purchase_price then failwith ("Incorrect amount"); + + // Type your solution below + Tezos.transaction (unit, purchase_price, vendor_address) +return True \ No newline at end of file diff --git a/src/Chapters/ChapterInteractions/squadron.ligo b/src/Chapters/ChapterPolymorphism/squadron.ligo similarity index 100% rename from src/Chapters/ChapterInteractions/squadron.ligo rename to src/Chapters/ChapterPolymorphism/squadron.ligo diff --git a/src/Chapters/ChapterInteractions/squadron_types.ligo b/src/Chapters/ChapterPolymorphism/squadron_types.ligo similarity index 100% rename from src/Chapters/ChapterInteractions/squadron_types.ligo rename to src/Chapters/ChapterPolymorphism/squadron_types.ligo diff --git a/src/Chapters/ChapterRecords/course.md b/src/Chapters/ChapterRecords/course.md index 8080007..a6fd9cc 100644 --- a/src/Chapters/ChapterRecords/course.md +++ b/src/Chapters/ChapterRecords/course.md @@ -58,7 +58,7 @@ function change_name (const u : user) : user is ## Your mission -1- Refactor the type of coordicanteas as a record instead of a tuple. Name the parameters x, y and z. +1- Refactor the type of coordinates as a record instead of a tuple. Name the parameters x, y and z. 2- Refactor *earth\_coordinates* with the record type. diff --git a/src/Chapters/ChapterTransactions/course.md b/src/Chapters/ChapterTransactions/course.md index b339f40..29ea827 100644 --- a/src/Chapters/ChapterTransactions/course.md +++ b/src/Chapters/ChapterTransactions/course.md @@ -10,7 +10,7 @@ Tezos.transaction (, ,
); where : -- _paramater_ is the entrypoints of another contract, or use _unit_ if you are transfering to a wallet address, +- _parameter_ is the entrypoints of another contract, or use _unit_ if you are transfering to a wallet address, - _mutez_ is the amount to transfer, - _address_ is the address of the other contract or the wallet. diff --git a/src/Chapters/ChapterTypes/course.md b/src/Chapters/ChapterTypes/course.md index fa95e7d..245f051 100644 --- a/src/Chapters/ChapterTypes/course.md +++ b/src/Chapters/ChapterTypes/course.md @@ -1,8 +1,8 @@ # Chapter 2 : Types -Welcome onboard captain, I'm the ship's mechanics. The first thing to do before departing is to define your ship's paramaters. Go ahead! +Welcome onboard captain, I'm the ship's mechanic. The first thing to do before departing is to define your ship's parameters. Go ahead! -LIGO is strongly and statically typed language. This means that the compiler checks how your contract processes data. If it passes the test, your contract will not fail at run-time due to inconsistent assumptions on your data. This is called type checking. +LIGO is a strongly and statically typed language. This means that the compiler checks how your contract processes data. If it passes the test, your contract will not fail at run-time due to inconsistent assumptions on your data. This is called type checking. ## Built-in types diff --git a/src/Chapters/ChapterVariant/course.md b/src/Chapters/ChapterVariant/course.md index 988766b..88918f9 100644 --- a/src/Chapters/ChapterVariant/course.md +++ b/src/Chapters/ChapterVariant/course.md @@ -1,4 +1,4 @@ -# Chapter 12 : Unit, Variant, Option and Pattern matching +# Chapter 12 : Unit, Variant and Pattern matching Captain, before we go, you may want to setup your commands to set the ship code and go to a destination. @@ -21,9 +21,9 @@ A variant type is a user-defined or a built-in type (in case of options) that de Here is how we define a coin as being either head or tail (and nothing else): ``` -type Coin is Head | Tail -const head : Coin = Head -const tail : Coin = Tail +type coin is Head | Tail +const head : coin = Head +const tail : coin = Tail ``` The names Head and Tail in the definition of the type coin are called data constructors, or variants. In this particular, they carry no information beyond their names, so they are called constant constructors. @@ -31,45 +31,36 @@ The names Head and Tail in the definition of the type coin are called data const In general, it is interesting for variants to carry some information, and thus go beyond enumerated types. In the following, we show how to define different kinds of users of a system. ``` -type Id is nat +type id is nat -type User is -Admin of Id -| Manager of Id +type user is + Admin of id +| Manager of id | Guest -const user : User = Admin (1000n) -const guest : User = Guest +const admin : user = Admin (1000n) +const guest : user = Guest ``` In LIGO, a constant constructor is equivalent to the same constructor taking an argument of type unit, so, for example, Guest is the same value as Guest (unit). -## Option - -The option type is a predefined variant type that is used to express whether there is a value of some type or none. This is especially useful when calling a partial function, that is, a function that is not defined for some inputs. In that case, the value of the option type would be None, otherwise Some (v), where v is some meaningful value of any type. An example in arithmetic is the division operation: - -``` -function div (const a : nat; const b : nat) : option (nat) is -if b = 0n then (None: option (nat)) else Some (a/b) -``` - ## Pattern matching Pattern matching is similiar to the switch construct in Javascript, and can be used to route the program's control flow based on the value of a variant. Consider for example the definition of a function flip that flips a coin. ``` -type Coin is Head | Tail +type coin is Head | Tail -function flip (const coin : Coin) : coin is -case coin of -Head -> Tail +function flip (const input_coin : coin) : coin is +case input_coin of + Head -> Tail | Tail -> Head end ``` ## Your mission -1- Create the type _Action_ as a variant. +1- Create the type _parameter_ as a variant. 2- Define the first option of the variant as *Set\_ship\_code* which will be our action to set the ship code. Notice this will take a string as an input. diff --git a/src/Chapters/ChapterVariant/solution.ligo b/src/Chapters/ChapterVariant/solution.ligo index 7c29565..511ee27 100644 --- a/src/Chapters/ChapterVariant/solution.ligo +++ b/src/Chapters/ChapterVariant/solution.ligo @@ -1,4 +1,4 @@ // Type your solution below -type Action is +type parameter is Set_ship_code of string | Go_to of string diff --git a/src/Drawer/Drawer.view.tsx b/src/Drawer/Drawer.view.tsx index 163ebd6..5d6ef88 100644 --- a/src/Drawer/Drawer.view.tsx +++ b/src/Drawer/Drawer.view.tsx @@ -140,7 +140,7 @@ export const DrawerView = ({ showing, hideCallback, pathname, user, removeAuthUs hideCallback()}> - 21 - What's next? + What's next?