From e1dc4b02d39ac1f2d26333fb9bec8cd3a78e8309 Mon Sep 17 00:00:00 2001 From: Frank Hillard Date: Tue, 18 Aug 2020 19:25:02 +0200 Subject: [PATCH] 26, 27,28 --- .../Chapters/Camel/ChapterFA20/course.md | 55 ++++++++----------- .../Chapters/Camel/ChapterInterop/course.md | 34 ++++++------ .../Camel/ChapterPreprocessor/course.md | 4 +- .../Chapters/Pascal/ChapterFA20/course.md | 50 +++++++---------- .../Chapters/Pascal/ChapterInterop/course.md | 32 ++++++----- .../Pascal/ChapterPreprocessor/course.md | 4 +- .../Chapters/Reason/ChapterFA20/course.md | 50 ++++++++--------- .../Chapters/Reason/ChapterInterop/course.md | 34 ++++++------ .../Reason/ChapterPreprocessor/course.md | 4 +- 9 files changed, 125 insertions(+), 142 deletions(-) diff --git a/src/frontend/src/pages/Chapters/Camel/ChapterFA20/course.md b/src/frontend/src/pages/Chapters/Camel/ChapterFA20/course.md index f58edf0..cfb74b9 100644 --- a/src/frontend/src/pages/Chapters/Camel/ChapterFA20/course.md +++ b/src/frontend/src/pages/Chapters/Camel/ChapterFA20/course.md @@ -4,7 +4,7 @@ ## Definition -There are multiple dimensions and considerations while implementing a particular token smart contract. Tokens might be fungible or non-fungible. A variety of permission policies can be used to define how many tokens can be transferred, who can initiate a transfer, and who can receive tokens. A token contract can be designed to support a single token type (e.g. ERC-20 or ERC-721) or multiple token types (e.g. ERC-1155) to optimize batch transfers and atomic swaps of the tokens. +There are multiple considerations while implementing a particular token smart contract. Tokens might be fungible or non-fungible. A variety of permission policies can be used to define how many tokens can be transferred, who can initiate a transfer, and who can receive tokens. A token contract can be designed to support a single token type (e.g. ERC-20 or ERC-721) or multiple token types (e.g. ERC-1155) to optimize batch transfers and atomic swaps of the tokens. The FA2 standard proposes a _unified token contract interface_ that accommodates all mentioned concerns. It aims to provide significant expressivity to contract developers to create new types of tokens while maintaining a common interface standard for wallet integrators and external developers. @@ -12,9 +12,9 @@ In the following chapter on Financial Application 2.0 , we will focus on _TZIP-1 ## Architecture -FA2 proposes to leave it to implementers to handle common considerations such as defining the contract’s token type(s) (e.g. non-fungible vs. fungible vs. semi-fungible), administration and whitelisting, contract upgradability, and supply operations (e.g. mint/burn). +The FA2 standard proposes to leave it to implementers to handle common considerations such as defining the contract’s token type(s) (e.g. non-fungible vs. fungible vs. semi-fungible), administration and whitelisting, contract upgradability, and supply operations (e.g. mint/burn). -FA2 also leaves to implementers to decide on architecture pattern for handling permissioning. Permission can be implemented +The FA2 standard also leaves to implementers to decide on architecture pattern for handling permissioning. Permission can be implemented - in the the same contract as the core transfer behavior (i.e. a “monolith”), - in a transfer hook to another contract, @@ -22,7 +22,7 @@ FA2 also leaves to implementers to decide on architecture pattern for handling p ## Interface and library -The FA2 interface formalize a standard way to design tokens and thus describes a list of entry points (that must be implemented) and data structures related to those entry points. A more detailed decription of the interface is broken down in following sections. +The FA2 interface formalizes a standard way to design tokens and thus describes a list of entry points (that must be implemented) and data structures related to these entry points. A more detailed decription of the interface is broken down in following sections. In addition to the FA2 interface, the FA2 standard provides helper functions to manipulate data structures involved in FA2 interface. The FA2 library contains helper functions for : @@ -50,12 +50,11 @@ type fa2_entry_points = ### Metadata -FA2 token contracts MUST implement the *token\_metadata* entry point which get the metadata for multiple token types. +FA2 token contracts MUST implement the *token\_metadata* entry point which gets the metadata for multiple token types. It accepts a list of *token\_ids* and a callback contract, and sends back a list of *token\_metadata* records. -FA2 token amounts are represented by natural numbers (nat), and their granularity (the smallest amount of tokens which may be minted, burned, or -transferred) is always 1. +FA2 token amounts are represented by natural numbers (nat), and their granularity (the smallest amount of tokens which may be minted, burned, or transferred) is always 1. The _decimals_ property is the number of digits to use after the decimal point when displaying the token amounts. If 0, the asset is not divisible. Decimals are used for display purposes only and MUST NOT affect transfer operation. @@ -80,7 +79,7 @@ type token_metadata_param = { ### Balance of -FA2 token contracts MUST implement the _Balance of_ entry point which get the balance of multiple account/token pairs (because FA2 supports mutiple token). +FA2 token contracts MUST implement the _Balance of_ entry point which gets the balance of multiple account/token pairs (because FA2 supports multiple token). ``` | Balance_of of balance_of_param @@ -115,7 +114,7 @@ type balance_of_param = { ### Totalsupply -FA2 token contracts MUST implement the _Totalsupply_ entry point which get the total supply of tokens for multiple token types (because FA2 supports mutiple token). +FA2 token contracts MUST implement the _Totalsupply_ entry point which gets the total supply of tokens for multiple token types (because FA2 supports multiple token). ``` | Total_supply of total_supply_param @@ -145,7 +144,7 @@ type total_supply_param = { ### Transfer -FA2 token contracts MUST implement the _Transfer_ entry point which transfer tokens between and MUST ensure following rules. +FA2 token contracts MUST implement the _Transfer_ entry point which transfers tokens between owners and MUST ensure following rules. ``` | Transfer of transfer list @@ -157,20 +156,15 @@ FA2 token contracts MUST implement the transfer logic defined by the following r 1. Every transfer operation MUST be atomic. If the operation fails, all token transfers MUST be reverted, and token balances MUST remain unchanged. -2. The amount of a token transfer MUST NOT exceed the existing token owner's balance. If the transfer amount for the particular token type and token owner - exceeds the existing balance, the whole transfer operation MUST fail with the error mnemonic "INSUFFICIENT_BALANCE" +2. The amount of a token transfer MUST NOT exceed the existing token owner's balance. If the transfer amount for the particular token type and token owner exceeds the existing balance, the whole transfer operation MUST fail with the error mnemonic "INSUFFICIENT_BALANCE" -3. Core transfer behavior MAY be extended. If additional constraints on tokens transfer are required, FA2 token contract implementation MAY invoke additional - permission policies (transfer hook is the recommended design pattern to implement core behavior extension). (See Chapter FA2 - Hook) +3. Core transfer behavior MAY be extended. If additional constraints on tokens transfer are required, FA2 token contract implementation MAY invoke additional permission policies (transfer hook is the recommended design pattern to implement core behavior extension). (See Chapter FA2 - Hook). If the additional permission hook fails, the whole transfer operation MUST fail with a custom error mnemonic. -If the additional permission hook fails, the whole transfer operation MUST fail with a custom error mnemonic. - -4. Core transfer behavior MUST update token balances exactly as the operation parameters specify it. No changes to amount values or additional transfers are - allowed. +4. Core transfer behavior MUST update token balances exactly as the operation parameters specify it. No changes to amount values or additional transfers are allowed. #### Interface -It transfer tokens from a _from\__ account to possibly many destination accounts where each destination transfer describes the type of token, the amount of token, and receiver address. +It transfers tokens from a _from\__ account to possibly many destination accounts where each destination transfer describes the type of token, the amount of token, and receiver address. ``` type token_id = nat @@ -196,8 +190,7 @@ type transfer_aux = { ### Error Handling -This FA2 tandard defines the set of standard errors to make it easier to integrate FA2 contracts with wallets, DApps and other generic software, and enable -localization of user-visible error messages. +This FA2 standard defines the set of standard errors to make it easier to integrate FA2 contracts with wallets, DApps and other generic software, and enable localization of user-visible error messages. Each error code is a short abbreviated string mnemonic. An FA2 contract client (like another contract or a wallet) could use on-the-chain or off-the-chain registry to map the error code mnemonic to a user-readable, localized message. @@ -210,25 +203,23 @@ When error occurs, any FA2 contract entry point MUST fail with one of the follow #### Standard error mnemonics: -Error mnemonic - Description - -"TOKEN_UNDEFINED" - One of the specified *token\_ids* is not defined within the FA2 contract +"*TOKEN\_UNDEFINED*" - One of the specified *token\_ids* is not defined within the FA2 contract -"INSUFFICIENT_BALANCE" - A token owner does not have sufficient balance to transfer tokens from owner's account +"*INSUFFICIENT\_BALANCE*" - A token owner does not have sufficient balance to transfer tokens from owner's account -"TX_DENIED" - A transfer failed because of *operator\_transfer\_policy* == *No\_transfer* +"*TX\_DENIED*" - A transfer failed because of *operator\_transfer\_policy* == *No\_transfer* -"NOT_OWNER" - A transfer failed because *operator\_transfer\_policy* == *Owner\_transfer* and it is initiated not by the token owner +"*NOT\_OWNER*" - A transfer failed because *operator\_transfer\_policy* == *Owner\_transfer* and it is initiated not by the token owner -"NOT_OPERATOR" - A transfer failed because *operator\_transfer\_policy* == *Owner\_or\_operator\_transfer* and it is initiated neither by the token owner nor a permitted operator +"*NOT\_OPERATOR*" - A transfer failed because *operator\_transfer\_policy* == *Owner\_or\_operator\_transfer* and it is initiated neither by the token owner nor a permitted operator -"RECEIVER_HOOK_FAILED" - The receiver hook failed. This error MUST be raised by the hook implementation +"*RECEIVER\_HOOK\_FAILED*" - The receiver hook failed. This error MUST be raised by the hook implementation -"SENDER_HOOK_FAILED" - The sender failed. This error MUST be raised by the hook implementation +"*SENDER\_HOOK\_FAILED*" - The sender failed. This error MUST be raised by the hook implementation -"RECEIVER_HOOK_UNDEFINED" -Receiver hook is required by the permission behavior, but is not implemented by a receiver contract +"*RECEIVER\_HOOK\_UNDEFINED*" -Receiver hook is required by the permission behavior, but is not implemented by a receiver contract -"SENDER_HOOK_UNDEFINED" - Sender hook is required by the permission behavior, but is not implemented by a sender contract +"*SENDER\_HOOK\_UNDEFINED*" - Sender hook is required by the permission behavior, but is not implemented by a sender contract ## Your mission diff --git a/src/frontend/src/pages/Chapters/Camel/ChapterInterop/course.md b/src/frontend/src/pages/Chapters/Camel/ChapterInterop/course.md index 3ac35e2..c1b0b67 100644 --- a/src/frontend/src/pages/Chapters/Camel/ChapterInterop/course.md +++ b/src/frontend/src/pages/Chapters/Camel/ChapterInterop/course.md @@ -2,7 +2,9 @@ We need to hack aliens, decompile their code to understand how their informatic works -LIGO can work together with other smart contract languages on Tezos. However data structures might have different representations in Michelson and not correctly match the standard LIGO types. +Tezos smart contracts are written in Michelson language. The LIGO transpiler helps developers to produce Michelson scripts. However LIGO data structures might have different representations in Michelson. For example, LIGO allows to define a record (a structure containing many fields) but once transpiled in Michelson this record is transformed in a pair of pairs, and there can be many pairs of pairs representing the same record. + +In this chapter, we will see that some built-in functions are available in LIGO language in order to address this problem. ## Annotations @@ -27,7 +29,7 @@ will accept these definitions and fail with the ones that does not respect the t ### Entrypoints and annotations -As seen in chapter Polymorphism, a contract can be called by another contract. The predefined function *Tezos.get\_entrypoint\_opt* allows to call a specific entry point of the called contract. +As seen in the chapter Polymorphism, a contract can be called by another contract. The predefined function *Tezos.get\_entrypoint\_opt* allows to call a specific entry point of the called contract. Here is an example. Let's consider the following "Counter" contract : @@ -45,7 +47,7 @@ let main ((p, x): (parameter * storage)): (operation list * storage) = )) ``` -Thre following contract sends a transaction to the "Counter" contract. +The following contract sends a transaction to the "Counter" contract. ``` type storage = int @@ -66,15 +68,15 @@ let main (p, s: parameter * storage): operation list * storage = ( ) ``` -⚠️ Notice how we directly use the _%left_ entrypoint without mentioning the _%right_ entrypoint. This is done with the help of annotations. Without annotations it wouldn't be clear what our int would be referring to. +⚠️ Notice how we directly use the _%left_ entry point without mentioning the _%right_ entry point. This is done with the help of annotations. Without annotations it wouldn't be clear what our _int_ would be referring to. -These annotations works for _or_'s or _variant_ types in LIGO. +These annotations work for _or_'s or _variant_ types in LIGO. -## Interop with Michelson +## Interoperability with Michelson -To interop with existing Michelson code or for compatibility with some development tooling, LIGO has two special interop types: *michelson\_or* and *michelson\_pair*. These types give the flexibility to model the exact Michelson output, including field annotations. +To interoperate with existing Michelson code or for compatibility with some development tooling, LIGO has two special interoperability types: *michelson\_or* and *michelson\_pair*. These types give the flexibility to model the exact Michelson output, including field annotations. -Take for example the following Michelson type that we want to interop with: +Take for example the following Michelson type that we want to interoperate with: ``` (or @@ -114,7 +116,7 @@ let x: z_or = (M_right (y_1) : z_or) ## Helper functions -Conversions from Ligo types to Michelson types require a precise knowledge of data structures representation. +Conversions from Ligo types to Michelson types require a precise knowledge of the representation of data structures. So it becomes even more relevant with nested pairs because there are many possible decompositions of a record in pairs of pairs. @@ -158,7 +160,7 @@ Converting between different LIGO types and data structures can happen in two wa #### Pair -Conversion between the Michelson type and record type is handled with the functions *Layout.convert\_from\_left\_comb* and *Layout.convert\_to\_left\_comb*. +Conversion between the Michelson type and record type is handled with functions *Layout.convert\_from\_left\_comb* and *Layout.convert\_to\_left\_comb*. Here's an example of a left combed Michelson data structure using pairs: @@ -184,24 +186,24 @@ type l_record = { This snippet of code shows -\* how to use *Layout.convert\_from\_left\_comb* to transform a Michelsontype into a record type. -\* how to use *Layout.convert\_to\_left\_comb* to transform a record type into a Michelsontype. +\* how to use *Layout.convert\_from\_left\_comb* to transform a Michelson type into a record type. +\* how to use *Layout.convert\_to\_left\_comb* to transform a record type into a Michelson type. ``` -type Michelson= l_record michelson_pair_left_comb +type Michelson = l_record michelson_pair_left_comb let of_michelson (f: michelson) : l_record = let p: l_record = Layout.convert_from_left_comb f in p -let to_michelson (f: l_record) : Michelson= +let to_michelson (f: l_record) : Michelson = let p = Layout.convert_to_left_comb (f: l_record) in p ``` #### Variant -In the case of a left combed Michelson or data structure, that you want to translate to a variant, you can use the *michelson\_or\_left\_comb* type. +In the case of a left combed Michelson or a data structure, that you want to translate to a variant, you can use the *michelson\_or\_left\_comb* type. ``` type vari = @@ -286,6 +288,6 @@ let make_abstract_record (z: string) (y: int) (x: string) (w: bool) (v: int) : t ## Your mission -We want you to modify our "inventory" contract. As you can see the storage is mainly composed of an item inventory where each item is a right combed nested pairs. The contract possess a single entry point AddInventory. This _AddInventory_ function adds each element in the inventory (don't worry about duplicates it has already been taken care of). +We want you to modify our "inventory" contract. As you can see the storage is mainly composed of an item inventory where each item is a right combed nested pairs. The contract possesses a single entry point AddInventory. This _AddInventory_ function adds each element in the inventory (don't worry about duplicates it has already been taken care of). 1- Complete the implementation of the *update\_inventory* lambda function. This function takes a list of item as parameter and must transform each item in a combed pair structure and add this resulting structure in the storage inventory. (When naming your temporary variables, use *acc* for the accumulator name and *i* for the current item) diff --git a/src/frontend/src/pages/Chapters/Camel/ChapterPreprocessor/course.md b/src/frontend/src/pages/Chapters/Camel/ChapterPreprocessor/course.md index 1b0f881..04290ff 100644 --- a/src/frontend/src/pages/Chapters/Camel/ChapterPreprocessor/course.md +++ b/src/frontend/src/pages/Chapters/Camel/ChapterPreprocessor/course.md @@ -2,7 +2,7 @@ -Instead of writing the whole code in a single file, it is possible to split code into different files and include some external code into our file. The pre-processor is responsible to handle code inclusion. While working with multiple files we may encounter a problem of cyclic inclusion. To prevent such situation some pre-processor commands are available. +Instead of writing the LIGO code in a single file, it is possible to split the code into different files and include some external code into our file. The pre-processor is responsible for handling code inclusion. While working with multiple files we may encounter a problem of cyclic inclusion. To prevent such situation some pre-processor commands are available. * #if * #define @@ -53,7 +53,7 @@ let substr_special (s: string) : string = ⚠️ Notice that the conditionnal *#if* can be used to customize your includes. -⚠️ Notice that this pattern prevents from redefinition in case of cyclic inclusion. +⚠️ Notice that this pattern prevents variable or type redefinition in case of cyclic inclusion. ``` #if !X diff --git a/src/frontend/src/pages/Chapters/Pascal/ChapterFA20/course.md b/src/frontend/src/pages/Chapters/Pascal/ChapterFA20/course.md index 8aab52c..bc2793d 100644 --- a/src/frontend/src/pages/Chapters/Pascal/ChapterFA20/course.md +++ b/src/frontend/src/pages/Chapters/Pascal/ChapterFA20/course.md @@ -4,7 +4,7 @@ ## Definition -There are multiple dimensions and considerations while implementing a particular token smart contract. Tokens might be fungible or non-fungible. A variety of permission policies can be used to define how many tokens can be transferred, who can initiate a transfer, and who can receive tokens. A token contract can be designed to support a single token type (e.g. ERC-20 or ERC-721) or multiple token types (e.g. ERC-1155) to optimize batch transfers and atomic swaps of the tokens. +There are multiple considerations while implementing a particular token smart contract. Tokens might be fungible or non-fungible. A variety of permission policies can be used to define how many tokens can be transferred, who can initiate a transfer, and who can receive tokens. A token contract can be designed to support a single token type (e.g. ERC-20 or ERC-721) or multiple token types (e.g. ERC-1155) to optimize batch transfers and atomic swaps of the tokens. The FA2 standard proposes a _unified token contract interface_ that accommodates all mentioned concerns. It aims to provide significant expressivity to contract developers to create new types of tokens while maintaining a common interface standard for wallet integrators and external developers. @@ -12,9 +12,9 @@ In the following chapter on Financial Application 2.0 , we will focus on _TZIP-1 ## Architecture -FA2 proposes to leave it to implementers to handle common considerations such as defining the contract’s token type(s) (e.g. non-fungible vs. fungible vs. semi-fungible), administration and whitelisting, contract upgradability, and supply operations (e.g. mint/burn). +The FA2 standard proposes to leave it to implementers to handle common considerations such as defining the contract’s token type(s) (e.g. non-fungible vs. fungible vs. semi-fungible), administration and whitelisting, contract upgradability, and supply operations (e.g. mint/burn). -FA2 also leaves to implementers to decide on architecture pattern for handling permissioning. Permission can be implemented +The FA2 standard also leaves to implementers to decide on architecture pattern for handling permissioning. Permission can be implemented - in the the same contract as the core transfer behavior (i.e. a “monolith”), - in a transfer hook to another contract, @@ -22,7 +22,7 @@ FA2 also leaves to implementers to decide on architecture pattern for handling p ## Interface and library -The FA2 interface formalize a standard way to design tokens and thus describes a list of entry points (that must be implemented) and data structures related to those entry points. A more detailed decription of the interface is broken down in following sections. +The FA2 interface formalizes a standard way to design tokens and thus describes a list of entry points (that must be implemented) and data structures related to these entry points. A more detailed decription of the interface is broken down in following sections. In addition to the FA2 interface, the FA2 standard provides helper functions to manipulate data structures involved in FA2 interface. The FA2 library contains helper functions for : @@ -48,7 +48,7 @@ type fa2_entry_points is ### Balance of -FA2 token contracts MUST implement the _Balance of_ entry point which get the balance of multiple account/token pairs (because FA2 supports mutiple token). +FA2 token contracts MUST implement the _Balance of_ entry point which gets the balance of multiple account/token pairs (because FA2 supports multiple token). ``` | Balance_of of balance_of_params @@ -85,7 +85,7 @@ end ### Transfer -FA2 token contracts MUST implement the _Transfer_ entry point which transfer tokens between and MUST ensure following rules. +FA2 token contracts MUST implement the _Transfer_ entry point which transfers tokens between owners and MUST ensure following rules. ``` Transfer of transfer_params @@ -97,20 +97,15 @@ FA2 token contracts MUST implement the transfer logic defined by the following r 1. Every transfer operation MUST be atomic. If the operation fails, all token transfers MUST be reverted, and token balances MUST remain unchanged. -2. The amount of a token transfer MUST NOT exceed the existing token owner's balance. If the transfer amount for the particular token type and token owner - exceeds the existing balance, the whole transfer operation MUST fail with the error mnemonic "INSUFFICIENT_BALANCE" +2. The amount of a token transfer MUST NOT exceed the existing token owner's balance. If the transfer amount for the particular token type and token owner exceeds the existing balance, the whole transfer operation MUST fail with the error mnemonic "INSUFFICIENT_BALANCE" -3. Core transfer behavior MAY be extended. If additional constraints on tokens transfer are required, FA2 token contract implementation MAY invoke additional - permission policies (transfer hook is the recommended design pattern to implement core behavior extension). (See Chapter FA2 - Hook) +3. Core transfer behavior MAY be extended. If additional constraints on tokens transfer are required, FA2 token contract implementation MAY invoke additional permission policies (transfer hook is the recommended design pattern to implement core behavior extension). (See Chapter FA2 - Hook). If the additional permission hook fails, the whole transfer operation MUST fail with a custom error mnemonic. -If the additional permission hook fails, the whole transfer operation MUST fail with a custom error mnemonic. - -4. Core transfer behavior MUST update token balances exactly as the operation parameters specify it. No changes to amount values or additional transfers are - allowed. +4. Core transfer behavior MUST update token balances exactly as the operation parameters specify it. No changes to amount values or additional transfers are allowed. #### Interface -It transfer tokens from a _from\__ account to possibly many destination accounts where each destination transfer describes the type of token, the amount of token, and receiver address. +It transfers tokens from a _from\__ account to possibly many destination accounts where each destination transfer describes the type of token, the amount of token, and receiver address. ``` type token_id = nat @@ -136,7 +131,7 @@ type transfer_aux = { ### Metadata -FA2 token contracts MUST implement the *token\_metadata\_registry* entry point which get the metadata for multiple token types. +FA2 token contracts MUST implement the *token\_metadata\_registry* entry point which gets the metadata for multiple token types. It expects a callback contract, and sends back a list of *token\_metadata\_* records. @@ -166,8 +161,7 @@ end ### Error Handling -This FA2 tandard defines the set of standard errors to make it easier to integrate FA2 contracts with wallets, DApps and other generic software, and enable -localization of user-visible error messages. +This FA2 standard defines the set of standard errors to make it easier to integrate FA2 contracts with wallets, DApps and other generic software, and enable localization of user-visible error messages. Each error code is a short abbreviated string mnemonic. An FA2 contract client (like another contract or a wallet) could use on-the-chain or off-the-chain registry to map the error code mnemonic to a user-readable, localized message. @@ -180,25 +174,23 @@ When error occurs, any FA2 contract entry point MUST fail with one of the follow #### Standard error mnemonics: -Error mnemonic - Description - -"TOKEN_UNDEFINED" - One of the specified *token\_ids* is not defined within the FA2 contract +"*TOKEN\_UNDEFINED*" - One of the specified *token\_ids* is not defined within the FA2 contract -"INSUFFICIENT_BALANCE" - A token owner does not have sufficient balance to transfer tokens from owner's account +"*INSUFFICIENT\_BALANCE*" - A token owner does not have sufficient balance to transfer tokens from owner's account -"TX_DENIED" - A transfer failed because of *operator\_transfer\_policy* == *No\_transfer* +"*TX\_DENIED*" - A transfer failed because of *operator\_transfer\_policy* == *No\_transfer* -"NOT_OWNER" - A transfer failed because *operator\_transfer\_policy* == *Owner\_transfer* and it is initiated not by the token owner +"*NOT\_OWNER*" - A transfer failed because *operator\_transfer\_policy* == *Owner\_transfer* and it is initiated not by the token owner -"NOT_OPERATOR" - A transfer failed because *operator\_transfer\_policy* == *Owner\_or\_operator\_transfer* and it is initiated neither by the token owner nor a permitted operator +"*NOT\_OPERATOR*" - A transfer failed because *operator\_transfer\_policy* == *Owner\_or\_operator\_transfer* and it is initiated neither by the token owner nor a permitted operator -"RECEIVER_HOOK_FAILED" - The receiver hook failed. This error MUST be raised by the hook implementation +"*RECEIVER\_HOOK\_FAILED*" - The receiver hook failed. This error MUST be raised by the hook implementation -"SENDER_HOOK_FAILED" - The sender failed. This error MUST be raised by the hook implementation +"*SENDER\_HOOK\_FAILED*" - The sender failed. This error MUST be raised by the hook implementation -"RECEIVER_HOOK_UNDEFINED" -Receiver hook is required by the permission behavior, but is not implemented by a receiver contract +"*RECEIVER\_HOOK\_UNDEFINED*" -Receiver hook is required by the permission behavior, but is not implemented by a receiver contract -"SENDER_HOOK_UNDEFINED" - Sender hook is required by the permission behavior, but is not implemented by a sender contract +"*SENDER\_HOOK\_UNDEFINED*" - Sender hook is required by the permission behavior, but is not implemented by a sender contract ## Your mission diff --git a/src/frontend/src/pages/Chapters/Pascal/ChapterInterop/course.md b/src/frontend/src/pages/Chapters/Pascal/ChapterInterop/course.md index 06ac109..d89c341 100644 --- a/src/frontend/src/pages/Chapters/Pascal/ChapterInterop/course.md +++ b/src/frontend/src/pages/Chapters/Pascal/ChapterInterop/course.md @@ -2,7 +2,9 @@ We need to hack aliens, decompile their code to understand how their informatic works -LIGO can work together with other smart contract languages on Tezos. However data structures might have different representations in Michelson and not correctly match the standard LIGO types. +Tezos smart contracts are written in Michelson language. The LIGO transpiler helps developers to produce Michelson scripts. However LIGO data structures might have different representations in Michelson. For example, LIGO allows to define a record (a structure containing many fields) but once transpiled in Michelson this record is transformed in a pair of pairs, and there can be many pairs of pairs representing the same record. + +In this chapter, we will see that some built-in functions are available in LIGO language in order to address this problem. ## Annotations @@ -27,7 +29,7 @@ will accept these definitions and fail with the ones that does not respect the t ### Entrypoints and annotations -As seen in chapter Polymorphism, a contract can be called by another contract. The predefined function *Tezos.get\_entrypoint\_opt* allows to call a specific entry point of the called contract. +As seen in the chapter Polymorphism, a contract can be called by another contract. The predefined function *Tezos.get\_entrypoint\_opt* allows to call a specific entry point of the called contract. Here is an example. Let's consider the following contract : @@ -65,15 +67,15 @@ function main (const p: parameter; const s: storage): (list(operation) * storage } with result ``` -⚠️ Notice how we directly use the _%left_ entrypoint without mentioning the _%right_ entrypoint. This is done with the help of annotations. Without annotations it wouldn't be clear what our int would be referring to. +⚠️ Notice how we directly use the _%left_ entrypoint without mentioning the _%right_ entrypoint. This is done with the help of annotations. Without annotations it wouldn't be clear what our _int_ would be referring to. -These annotations works for _or_'s or _variant_ types in LIGO. +These annotations work for _or_'s or _variant_ types in LIGO. -## Interop with Michelson +## Interoperability with Michelson -To interop with existing Michelson code or for compatibility with some development tooling, LIGO has two special interop types: *michelson\_or* and *michelson\_pair*. These types give the flexibility to model the exact Michelson output, including field annotations. +To interoperate with existing Michelson code or for compatibility with some development tooling, LIGO has two special interoperability types: *michelson\_or* and *michelson\_pair*. These types give the flexibility to model the exact Michelson output, including field annotations. -Take for example the following Michelson type that we want to interop with: +Take for example the following Michelson type that we want to interoperate with: ``` (or @@ -113,7 +115,7 @@ const x: z_or = (M_right (y_1) : z_or); ## Helper functions -Conversions from Ligo types to Michelsontypes require a precise knowledge of data structures representation. +Conversions from Ligo types to Michelson types require a precise knowledge of the representation of data structures. So it becomes even more relevant with nested pairs because there are many possible decompositions of a record in pairs of pairs. @@ -157,7 +159,7 @@ Converting between different LIGO types and data structures can happen in two wa #### Pair -Conversion between the Michelson type and record type is handled with the functions *Layout.convert\_from\_left\_comb* and *Layout.convert\_to\_left\_comb*. +Conversion between the Michelson type and record type is handled with functions *Layout.convert\_from\_left\_comb* and *Layout.convert\_to\_left\_comb*. Here's an example of a left combed Michelson data structure using pairs: @@ -183,11 +185,11 @@ type l_record is record [ This snippet of code shows -\* how to use *Layout.convert\_from\_left\_comb* to transform a Michelsontype into a record type. -\* how to use *Layout.convert\_to\_left\_comb* to transform a record type into a Michelsontype. +\* how to use *Layout.convert\_from\_left\_comb* to transform a Michelson type into a record type. +\* how to use *Layout.convert\_to\_left\_comb* to transform a record type into a Michelson type. ``` -type Michelsonis michelson_pair_left_comb(l_record) +type Michelson is michelson_pair_left_comb(l_record) function of_michelson (const f: michelson) : l_record is block { @@ -195,7 +197,7 @@ function of_michelson (const f: michelson) : l_record is } with p -function to_michelson (const f: l_record) : Michelsonis +function to_michelson (const f: l_record) : Michelson is block { const p: Michelson= Layout.convert_to_left_comb ((f: l_record)) } @@ -204,7 +206,7 @@ function to_michelson (const f: l_record) : Michelsonis #### Variant -In the case of a left combed Michelson or data structure, that you want to translate to a variant, you can use the *michelson\_or\_left\_comb* type. +In the case of a left combed Michelson or a data structure, that you want to translate to a variant, you can use the *michelson\_or\_left\_comb* type. ``` type vari is @@ -318,6 +320,6 @@ function make_abstract_record (const z: string; const y: int; const x: string; c ## Your mission -We want you to modify our "inventory" contract. As you can see the storage is mainly composed of an item inventory where each item is a right combed nested pairs. The contract possess a single entry point AddInventory. This _AddInventory_ function adds each element in the inventory (don't worry about duplicates it has already been taken care of). +We want you to modify our "inventory" contract. As you can see the storage is mainly composed of an item inventory where each item is a right combed nested pairs. The contract possesses a single entry point AddInventory. This _AddInventory_ function adds each element in the inventory (don't worry about duplicates it has already been taken care of). 1- Complete the implementation of the *update_inventory* lambda function. This function takes a list of item as parameter and must transform each item in a combed pair structure and add this resulting structure in the storage inventory. (When naming your temporary variables, use *acc* for the accumulator name and *i* for the current item) diff --git a/src/frontend/src/pages/Chapters/Pascal/ChapterPreprocessor/course.md b/src/frontend/src/pages/Chapters/Pascal/ChapterPreprocessor/course.md index 93c39e0..788ef7c 100644 --- a/src/frontend/src/pages/Chapters/Pascal/ChapterPreprocessor/course.md +++ b/src/frontend/src/pages/Chapters/Pascal/ChapterPreprocessor/course.md @@ -2,7 +2,7 @@ -Instead of writing the smart contract code in a single file, it is possible to split it into different files and make code inclusion. The pre-processor is responsible for handling code inclusion. While working with multiple files we may encounter a problem of cyclic inclusion. To prevent such situation some pre-processor commands are available. +Instead of writing the LIGO code in a single file, it is possible to split the code into different files and include some external code into our file. The pre-processor is responsible for handling code inclusion. While working with multiple files we may encounter a problem of cyclic inclusion. To prevent such situation some pre-processor commands are available. * #if * #define @@ -56,7 +56,7 @@ function substr_special (const s: string) : string is ⚠️ Notice that the conditionnal *#if* can be used to customize your includes. -⚠️ Notice that this pattern prevents from redefinition in case of cyclic inclusion. +⚠️ Notice that this pattern prevents variable or type redefinition in case of cyclic inclusion. ``` #if !X diff --git a/src/frontend/src/pages/Chapters/Reason/ChapterFA20/course.md b/src/frontend/src/pages/Chapters/Reason/ChapterFA20/course.md index 9ee51e3..cc71eec 100644 --- a/src/frontend/src/pages/Chapters/Reason/ChapterFA20/course.md +++ b/src/frontend/src/pages/Chapters/Reason/ChapterFA20/course.md @@ -4,7 +4,7 @@ ## Definition -There are multiple dimensions and considerations while implementing a particular token smart contract. Tokens might be fungible or non-fungible. A variety of permission policies can be used to define how many tokens can be transferred, who can initiate a transfer, and who can receive tokens. A token contract can be designed to support a single token type (e.g. ERC-20 or ERC-721) or multiple token types (e.g. ERC-1155) to optimize batch transfers and atomic swaps of the tokens. +There are multiple considerations while implementing a particular token smart contract. Tokens might be fungible or non-fungible. A variety of permission policies can be used to define how many tokens can be transferred, who can initiate a transfer, and who can receive tokens. A token contract can be designed to support a single token type (e.g. ERC-20 or ERC-721) or multiple token types (e.g. ERC-1155) to optimize batch transfers and atomic swaps of the tokens. The FA2 standard proposes a _unified token contract interface_ that accommodates all mentioned concerns. It aims to provide significant expressivity to contract developers to create new types of tokens while maintaining a common interface standard for wallet integrators and external developers. @@ -12,9 +12,9 @@ In the following chapter on Financial Application 2.0 , we will focus on _TZIP-1 ## Architecture -FA2 proposes to leave it to implementers to handle common considerations such as defining the contract’s token type(s) (e.g. non-fungible vs. fungible vs. semi-fungible), administration and whitelisting, contract upgradability, and supply operations (e.g. mint/burn). +The FA2 standard proposes to leave it to implementers to handle common considerations such as defining the contract’s token type(s) (e.g. non-fungible vs. fungible vs. semi-fungible), administration and whitelisting, contract upgradability, and supply operations (e.g. mint/burn). -FA2 also leaves to implementers to decide on architecture pattern for handling permissioning. Permission can be implemented +The FA2 standard also leaves to implementers to decide on architecture pattern for handling permissioning. Permission can be implemented - in the the same contract as the core transfer behavior (i.e. a “monolith”), - in a transfer hook to another contract, @@ -22,13 +22,13 @@ FA2 also leaves to implementers to decide on architecture pattern for handling p ## Interface and library -The FA2 interface formalize a standard way to design tokens and thus describes a list of entry points (that must be implemented) and data structures related to those entry points. A more detailed decription of the interface is broken down in following sections. +The FA2 interface formalizes a standard way to design tokens and thus describes a list of entry points (that must be implemented) and data structures related to these entry points. A more detailed decription of the interface is broken down in following sections. In addition to the FA2 interface, the FA2 standard provides helper functions to manipulate data structures involved in FA2 interface. The FA2 library contains helper functions for : * a generic behavior and transfer hook implementation (behavior based on *permissions\_descriptor*), -- converting/manipulating data structures, +- converting data structures, - defining hooks between contracts when transfer is emitted, - defining operators for managing allowance. @@ -51,7 +51,7 @@ type parameter = The FA2 client (contracts using our token) may need to know the balance of a owner. The FA2 standard specifies an entry point _Balance of_ which use a callback in order to send the balance information to the calling contract. -FA2 token contracts MUST implement the _Balance of_ entry point which get the balance of multiple account/token pairs (because FA2 supports mutiple token). +FA2 token contracts MUST implement the _Balance of_ entry point which gets the balance of multiple account/token pairs (because FA2 supports multiple token). ``` | Balance_of of balance_of_param @@ -110,7 +110,7 @@ Most basic feature of a token is to provide a way to exchange tokens between own | Transfer of transfer list ``` -FA2 token contracts MUST implement the _Transfer_ entry point which transfer tokens between owners and MUST ensure following rules. +FA2 token contracts MUST implement the _Transfer_ entry point which transfers tokens between owners and MUST ensure following rules. #### Rules @@ -118,18 +118,15 @@ FA2 token contracts MUST implement the transfer logic defined by the following r 1. Every transfer operation MUST be atomic. If the operation fails, all token transfers MUST be reverted, and token balances MUST remain unchanged. -2. The amount of a token transfer MUST NOT exceed the existing token owner's balance. If the transfer amount for the particular token type and token owner - exceeds the existing balance, the whole transfer operation MUST fail with the error mnemonic "INSUFFICIENT_BALANCE" +2. The amount of a token transfer MUST NOT exceed the existing token owner's balance. If the transfer amount for the particular token type and token owner exceeds the existing balance, the whole transfer operation MUST fail with the error mnemonic "INSUFFICIENT_BALANCE" -3. Core transfer behavior MAY be extended. If additional constraints on tokens transfer are required, FA2 token contract implementation MAY invoke additional permission policies (transfer hook is the recommended design pattern to implement core behavior extension). (See Chapter FA2 - Hook) - -If the additional permission hook fails, the whole transfer operation MUST fail with a custom error mnemonic. +3. Core transfer behavior MAY be extended. If additional constraints on tokens transfer are required, FA2 token contract implementation MAY invoke additional permission policies (transfer hook is the recommended design pattern to implement core behavior extension). (See Chapter FA2 - Hook). If the additional permission hook fails, the whole transfer operation MUST fail with a custom error mnemonic. 4. Core transfer behavior MUST update token balances exactly as the operation parameters specify it. No changes to amount values or additional transfers are allowed. #### Interface -It transfer tokens from a _from\__ account to possibly many destination accounts where each destination transfer describes the type of token, the amount of token, and receiver address. +It transfers tokens from a _from\__ account to possibly many destination accounts where each destination transfer describes the type of token, the amount of token, and receiver address. ``` type tokenId = nat; @@ -179,7 +176,7 @@ The _decimals_ property is the number of digits to use after the decimal point w #### Interface -A basic feature of a token is to provide a meatadata related to the token. The FA2 standard speficies an entry point _Token\_metadata\_registry_ for this. +A basic feature of a token is to provide a metadata related to the token. The FA2 standard speficies an entry point _Token\_metadata\_registry_ for this. ``` | Token_metadata_registry(tokenMetadataRegistryParameter) @@ -221,8 +218,7 @@ let tokenMetadataRegistry = ((tokenMetadataRegistryParameter, storage): (tokenMe ### Error Handling -This FA2 tandard defines the set of standard errors to make it easier to integrate FA2 contracts with wallets, DApps and other generic software, and enable -localization of user-visible error messages. +This FA2 standard defines the set of standard errors to make it easier to integrate FA2 contracts with wallets, DApps and other generic software, and enable localization of user-visible error messages. Each error code is a short abbreviated string mnemonic. An FA2 contract client (like another contract or a wallet) could use on-the-chain or off-the-chain registry to map the error code mnemonic to a user-readable, localized message. @@ -235,29 +231,27 @@ When error occurs, any FA2 contract entry point MUST fail with one of the follow #### Standard error mnemonics: -Error mnemonic - Description - -"TOKEN_UNDEFINED" - One of the specified *token\_ids* is not defined within the FA2 contract +"*TOKEN\_UNDEFINED*" - One of the specified *token\_ids* is not defined within the FA2 contract -"INSUFFICIENT_BALANCE" - A token owner does not have sufficient balance to transfer tokens from owner's account +"*INSUFFICIENT\_BALANCE*" - A token owner does not have sufficient balance to transfer tokens from owner's account -"TX_DENIED" - A transfer failed because of *operator\_transfer\_policy* == *No\_transfer* +"*TX\_DENIED*" - A transfer failed because of *operator\_transfer\_policy* == *No\_transfer* -"NOT_OWNER" - A transfer failed because *operator\_transfer\_policy* == *Owner\_transfer* and it is initiated not by the token owner +"*NOT\_OWNER*" - A transfer failed because *operator\_transfer\_policy* == *Owner\_transfer* and it is initiated not by the token owner -"NOT_OPERATOR" - A transfer failed because *operator\_transfer\_policy* == *Owner\_or\_operator\_transfer* and it is initiated neither by the token owner nor a permitted operator +"*NOT\_OPERATOR*" - A transfer failed because *operator\_transfer\_policy* == *Owner\_or\_operator\_transfer* and it is initiated neither by the token owner nor a permitted operator -"RECEIVER_HOOK_FAILED" - The receiver hook failed. This error MUST be raised by the hook implementation +"*RECEIVER\_HOOK\_FAILED*" - The receiver hook failed. This error MUST be raised by the hook implementation -"SENDER_HOOK_FAILED" - The sender failed. This error MUST be raised by the hook implementation +"*SENDER\_HOOK\_FAILED*" - The sender failed. This error MUST be raised by the hook implementation -"RECEIVER_HOOK_UNDEFINED" -Receiver hook is required by the permission behavior, but is not implemented by a receiver contract +"*RECEIVER\_HOOK\_UNDEFINED*" -Receiver hook is required by the permission behavior, but is not implemented by a receiver contract -"SENDER_HOOK_UNDEFINED" - Sender hook is required by the permission behavior, but is not implemented by a sender contract +"*SENDER\_HOOK\_UNDEFINED*" - Sender hook is required by the permission behavior, but is not implemented by a sender contract ## Your mission -We are working on a fungible token compliant with the FA2 standard. We want you to complete the existing implementation of token. The *Balance\_Of* entry point is not yet implemented , please finish the job ! +We are working on a fungible token compliant with the FA2 standard. We want you to complete the existing implementation of token. The *Balance\_Of* entry point is not yet implemented, please finish the job ! The function *balanceOfRequestsIterator* is responsible for processing each request and providing a response to each request.As you can see, a request is of type *balanceOfRequestMichelson* diff --git a/src/frontend/src/pages/Chapters/Reason/ChapterInterop/course.md b/src/frontend/src/pages/Chapters/Reason/ChapterInterop/course.md index 137562c..0dc722e 100644 --- a/src/frontend/src/pages/Chapters/Reason/ChapterInterop/course.md +++ b/src/frontend/src/pages/Chapters/Reason/ChapterInterop/course.md @@ -2,7 +2,9 @@ We need to hack aliens, decompile their code to understand how their informatic works -LIGO can work together with other smart contract languages on Tezos. However data structures might have different representations in Michelson and not correctly match the standard LIGO types. +Tezos smart contracts are written in Michelson language. The LIGO transpiler helps developers to produce Michelson scripts. However LIGO data structures might have different representations in Michelson. For example, LIGO allows to define a record (a structure containing many fields) but once transpiled in Michelson this record is transformed in a pair of pairs, and there can be many pairs of pairs representing the same record. + +In this chapter, we will see that some built-in functions are available in LIGO language in order to address this problem. ## Annotations @@ -27,7 +29,7 @@ will accept these definitions and fail with the ones that does not respect the t ### Entrypoints and annotations -As seen in chapter Polymorphism, a contract can be called by another contract. The predefined function *Tezos.get\_entrypoint\_opt* allows to call a specific entry point of the called contract. +As seen in the chapter Polymorphism, a contract can be called by another contract. The predefined function *Tezos.get\_entrypoint\_opt* allows to call a specific entry point of the called contract. Here is an example. Let's consider the following "Counter" contract : @@ -46,7 +48,7 @@ let main = ((p, x): (parameter, storage)): (list(operation), storage) => { }; ``` -Thre following contract sends a transaction to the "Counter" contract. +The following contract sends a transaction to the "Counter" contract. ``` type storage = int; @@ -67,15 +69,15 @@ let main = ((p, s): (parameter, storage)): (list(operation), storage) => { }; ``` -⚠️ Notice how we directly use the _%left_ entrypoint without mentioning the _%right_ entrypoint. This is done with the help of annotations. Without annotations it wouldn't be clear what our int would be referring to. +⚠️ Notice how we directly use the _%left_ entrypoint without mentioning the _%right_ entrypoint. This is done with the help of annotations. Without annotations it wouldn't be clear what our _int_ would be referring to. -These annotations works for _or_'s or _variant_ types in LIGO. +These annotations work for _or_'s or _variant_ types in LIGO. -## Interop with Michelson +## Interoperability with Michelson -To interop with existing Michelson code or for compatibility with some development tooling, LIGO has two special interop types: *michelson\_or* and *michelson\_pair*. These types give the flexibility to model the exact Michelson output, including field annotations. +To interoperate with existing Michelson code or for compatibility with some development tooling, LIGO has two special interoperability types: *michelson\_or* and *michelson\_pair*. These types give the flexibility to model the exact Michelson output, including field annotations. -Take for example the following Michelson type that we want to interop with: +Take for example the following Michelson type that we want to interoperate with: ``` (or @@ -115,7 +117,7 @@ let x: z_or = (M_right (y_1) : z_or) ## Helper functions -Conversions from Ligo types to Michelson types require a precise knowledge of data structures representation. +Conversions from Ligo types to Michelson types require a precise knowledge of the representation of data structures. So it becomes even more relevant with nested pairs because there are many possible decompositions of a record in pairs of pairs. @@ -159,7 +161,7 @@ Converting between different LIGO types and data structures can happen in two wa #### Pair -Conversion between the Michelson type and record type is handled with the functions *Layout.convert\_from\_left\_comb* and *Layout.convert\_to\_left\_comb*. +Conversion between the Michelson type and record type is handled with functions *Layout.convert\_from\_left\_comb* and *Layout.convert\_to\_left\_comb*. Here's an example of a left combed Michelson data structure using pairs: @@ -185,18 +187,18 @@ type l_record = { This snippet of code shows -* how to use *Layout.convert\_from\_left\_comb* to transform a Michelsontype into a record type. -* how to use *Layout.convert\_to\_left\_comb* to transform a record type into a Michelsontype. +* how to use *Layout.convert\_from\_left\_comb* to transform a Michelson type into a record type. +* how to use *Layout.convert\_to\_left\_comb* to transform a record type into a Michelson type. ``` -type Michelson= michelson_pair_left_comb(l_record); +type Michelson = michelson_pair_left_comb(l_record); let of_michelson = (f: michelson) : l_record => { let p: l_record = Layout.convert_from_left_comb(f); p }; -let to_michelson = (f: l_record) : Michelson=> { +let to_michelson = (f: l_record) : Michelson => { let p = Layout.convert_to_left_comb(f: l_record); p } @@ -204,7 +206,7 @@ let to_michelson = (f: l_record) : Michelson=> { #### Variant -In the case of a left combed Michelson or data structure, that you want to translate to a variant, you can use the *michelson\_or\_left\_comb* type. +In the case of a left combed Michelson or a data structure, that you want to translate to a variant, you can use the *michelson\_or\_left\_comb* type. ``` type vari = @@ -298,6 +300,6 @@ let make_abstract_record = (z: string, y: int, x: string, w: bool, v: int) : tes ## Your mission -We want you to modify our "inventory" contract. As you can see the storage is mainly composed of an item inventory where each item is a right combed nested pairs. The contract possess a single entry point AddInventory. This _AddInventory_ function adds each element in the inventory (don't worry about duplicates it has already been taken care of). +We want you to modify our "inventory" contract. As you can see the storage is mainly composed of an item inventory where each item is a right combed nested pairs. The contract possesses a single entry point AddInventory. This _AddInventory_ function adds each element in the inventory (don't worry about duplicates it has already been taken care of). 1- Complete the implementation of the *update_inventory* lambda function. This function takes a list of item as parameter and must transform each item in a combed pair structure and add this resulting structure in the storage inventory. (When naming your temporary variables, use *acc* for the accumulator name and *i* for the current item) diff --git a/src/frontend/src/pages/Chapters/Reason/ChapterPreprocessor/course.md b/src/frontend/src/pages/Chapters/Reason/ChapterPreprocessor/course.md index 6323a2a..52d910c 100644 --- a/src/frontend/src/pages/Chapters/Reason/ChapterPreprocessor/course.md +++ b/src/frontend/src/pages/Chapters/Reason/ChapterPreprocessor/course.md @@ -2,7 +2,7 @@ -Instead of writing the whole code in a single file, it is possible to split code into different files and include some external code into our file. The pre-processor is responsible to handle code inclusion. While working with multiple files we may encounter a problem of cyclic inclusion. To prevent such situation some pre-processor commands are available. +Instead of writing the LIGO code in a single file, it is possible to split the code into different files and include some external code into our file. The pre-processor is responsible for handling code inclusion. While working with multiple files we may encounter a problem of cyclic inclusion. To prevent such situation some pre-processor commands are available. * #if * #define @@ -53,7 +53,7 @@ let substr_special = (s: string) : string => ⚠️ Notice that the conditionnal *#if* can be used to customize your includes. -⚠️ Notice that this pattern prevents from redefinition in case of cyclic inclusion. +⚠️ Notice that this pattern prevents variable or type redefinition in case of cyclic inclusion. ``` #if !X