Skip to content
This repository has been archived by the owner on Jun 20, 2024. It is now read-only.

Commit

Permalink
📝 Add structure for Chapter 2
Browse files Browse the repository at this point in the history
  • Loading branch information
omarespejel committed Apr 14, 2023
1 parent 44349b0 commit b473556
Show file tree
Hide file tree
Showing 21 changed files with 796 additions and 562 deletions.
18 changes: 15 additions & 3 deletions chapters/modules/chapter_2/nav.adoc
Original file line number Diff line number Diff line change
@@ -1,4 +1,16 @@
* xref:index.adoc[Chapter 2: Smart Contracts in Cairo]
** xref:programming.adoc[2.1 Programming in Cairo]
** xref:types.adoc[2.1 Types in Cairo]
** xref:functions.adoc[2.2 Functions and Modules in Cairo]
** xref:structure.adoc[2.3 The Structure of a Cairo Smart Contract]
*** xref:imports.adoc[2.3.1 Imports]
*** xref:storage.adoc[2.3.2 Storage]
*** xref:constructor.adoc[2.3.3 Contructor Function]
*** xref:getter.adoc[2.3.4 Getter Functions (View Functions)]
*** xref:asserts.adoc[2.3.5 Asserts and Error Handling]
*** xref:external.adoc[2.3.6 External Functions]
*** xref:internal.adoc[2.3.7 Internal Functions]
*** xref:event.adoc[2.3.8 Event Functions]
** xref:scarb.adoc[2.4 Introduction to Scarb]
** xref:traits.adoc[2.5 Traits in Cairo]
** xref:impl.adoc[2.6 Implementations in Cairo]
** xref:enums.adoc[2.7 Enums in Cairo]
34 changes: 34 additions & 0 deletions chapters/modules/chapter_2/pages/asserts.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
[id="asserts"]

= Asserts and Error Handling in Cairo

In Cairo, the `assert` statement is used to validate inputs, enforce constraints, and handle errors. This statement checks if a given condition is true and throws an error message if it is not.

In the Vote contract, the `assert` statement is used in several places to ensure proper input validation and error handling:

[source,rust]
----
assert(vote == 0_u8 | vote == 1_u8, 'VOTE_0_OR_1');
assert(is_voter == true, 'USER_NOT_REGISTERED');
assert(can_vote == true, 'USER_ALREADY_VOTED');
----

Some key points about the `assert` statement in Cairo are:

1. The `assert` statement checks if a condition is true. If the condition is not true, the contract execution is halted, and an error message is thrown.

2. Error messages are specified as strings, following the condition. In the example above, 'VOTE_0_OR_1', 'USER_NOT_REGISTERED', and 'USER_ALREADY_VOTED' are the error messages.

3. The `assert` statement is helpful for input validation, ensuring that only valid inputs are processed by the contract.

== Contributing

[quote, The Starknet Community]
____
*Unleash Your Passion to Perfect StarkNetBook*
StarkNetBook is a work in progress, and your passion, expertise, and unique insights can help transform it into something truly exceptional. Don't be afraid to challenge the status quo or break the Book! Together, we can create an invaluable resource that empowers countless others. :emoji-rocket: :emoji-sparkles:
Embrace the excitement of contributing to something bigger than ourselves. If you see room for improvement, seize the opportunity! Check out our https://github.com/starknet-edu/starknetbook/blob/main/CONTRIBUTING.adoc[guidelines] and join our vibrant community. Let's fearlessly build Starknet!
____
11 changes: 11 additions & 0 deletions chapters/modules/chapter_2/pages/calling_invoking.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,14 @@ Let's interact with our deployed voting contract.
* Calling contracts refer to interacting with contract functions with the `@view` entry point (decorator). Since we are not altering the state of the network, and hence we do not need to pay fees, we do not need to sign the operation.
* Invoking contracts is interacting with contract functions with the `@external` entry point. We need to sign the transaction and pay the operation fee.

== Contributing

[quote, The Starknet Community]
____
*Unleash Your Passion to Perfect StarkNetBook*
StarkNetBook is a work in progress, and your passion, expertise, and unique insights can help transform it into something truly exceptional. Don't be afraid to challenge the status quo or break the Book! Together, we can create an invaluable resource that empowers countless others. :emoji-rocket: :emoji-sparkles:
Embrace the excitement of contributing to something bigger than ourselves. If you see room for improvement, seize the opportunity! Check out our https://github.com/starknet-edu/starknetbook/blob/main/CONTRIBUTING.adoc[guidelines] and join our vibrant community. Let's fearlessly build Starknet!
____

69 changes: 69 additions & 0 deletions chapters/modules/chapter_2/pages/constructor.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
[id="constructor"]

= Constructor function in Cairo

A constructor is a special function that initializes a Cairo contract when it is deployed on the blockchain. The constructor is called only once, at the time of deployment, and is responsible for setting up the initial state of the contract.

In the `Vote` contract, there are two constructors:

1. A constructor that takes three individual `ContractAddress` parameters representing the addresses of the registered voters.
2. An alternative constructor that takes an array of `ContractAddress` values, which can be used to initialize the contract with a variable number of registered voters. (This constructor is commented out in the example provided, but it demonstrates how you can implement different constructor variations in a Cairo contract.)

Let's examine the first constructor in more detail:

[source,rust]
----
#[constructor]
fn constructor(voter_1: ContractAddress, voter_2: ContractAddress, voter_3: ContractAddress) {
// Register all voters by calling the _register_voters function
_register_voters(voter_1, voter_2, voter_3);
// Initialize the vote count to 0
yes_votes::write(0_u8);
no_votes::write(0_u8);
}
----

This constructor does the following:

* Registers the three voters by calling the `_register_voters` function and passing the three `ContractAddress` values. The `_register_voters` function updates the `registered_voter` and `can_vote` mapping structures in the storage.
* Initializes the `yes_votes` and `no_votes` storage variables to 0 by calling the `write` function with an initial value of `0_u8` (an unsigned 8-bit integer).

Now, let's briefly examine the alternative constructor. Please note that you can only have one constructor per contract, so you can either use the first constructor or the second one, but not both.

[source,rust]
----
#[constructor]
fn constructor(registered_addresses: Array::<ContractAddress>) {
// Get the number of registered voters
let registered_voters_len: usize = registered_addresses.len();
// Register all voters by calling the _register_voters recursive function
// with the array of addresses and its length as index
_register_voters(ref registered_addresses, registered_voters_len);
// Initialize the vote count to 0
yes_votes::write(0_u8);
no_votes::write(0_u8);
}
----

The alternative constructor:

* Takes an `Array` of `ContractAddress` values representing the addresses of the registered voters.
* Calculates the number of registered voters using the `len` function. This will be the index of the last voter in the array and will be used in the recursive function (next point).
* Registers all voters by calling the `_register_voters` function, which uses a recursive approach in this case.
* Initializes the `yes_votes` and `no_votes` storage variables to 0, just like the first constructor.

The use of two constructors demonstrates how you can provide different ways to initialize the contract based on the input parameters or the desired functionality.

== Contributing

[quote, The Starknet Community]
____
*Unleash Your Passion to Perfect StarkNetBook*
StarkNetBook is a work in progress, and your passion, expertise, and unique insights can help transform it into something truly exceptional. Don't be afraid to challenge the status quo or break the Book! Together, we can create an invaluable resource that empowers countless others. :emoji-rocket: :emoji-sparkles:
Embrace the excitement of contributing to something bigger than ourselves. If you see room for improvement, seize the opportunity! Check out our https://github.com/starknet-edu/starknetbook/blob/main/CONTRIBUTING.adoc[guidelines] and join our vibrant community. Let's fearlessly build Starknet!
____
15 changes: 15 additions & 0 deletions chapters/modules/chapter_2/pages/enums.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[id="structure"]

= The Structure of a Cairo Smart Contract


== Contributing

[quote, The Starknet Community]
____
*Unleash Your Passion to Perfect StarkNetBook*
StarkNetBook is a work in progress, and your passion, expertise, and unique insights can help transform it into something truly exceptional. Don't be afraid to challenge the status quo or break the Book! Together, we can create an invaluable resource that empowers countless others. :emoji-rocket: :emoji-sparkles:
Embrace the excitement of contributing to something bigger than ourselves. If you see room for improvement, seize the opportunity! Check out our https://github.com/starknet-edu/starknetbook/blob/main/CONTRIBUTING.adoc[guidelines] and join our vibrant community. Let's fearlessly build Starknet!
____
16 changes: 16 additions & 0 deletions chapters/modules/chapter_2/pages/event.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[id="structure"]

= The Structure of a Cairo Smart Contract



== Contributing

[quote, The Starknet Community]
____
*Unleash Your Passion to Perfect StarkNetBook*
StarkNetBook is a work in progress, and your passion, expertise, and unique insights can help transform it into something truly exceptional. Don't be afraid to challenge the status quo or break the Book! Together, we can create an invaluable resource that empowers countless others. :emoji-rocket: :emoji-sparkles:
Embrace the excitement of contributing to something bigger than ourselves. If you see room for improvement, seize the opportunity! Check out our https://github.com/starknet-edu/starknetbook/blob/main/CONTRIBUTING.adoc[guidelines] and join our vibrant community. Let's fearlessly build Starknet!
____
9 changes: 8 additions & 1 deletion chapters/modules/chapter_2/pages/explorers.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,11 @@ The following block explorers provide information on StarkNet.

== Contributing

🎯 +++<strong>+++STARKer: +++</strong>+++ This book is an open source effort, made possible only by contributions from readers like you. If you are interested in making this resource better for other users - please suggest a change by following the instructions https://github.com/starknet-edu/starknetbook/blob/main/CONTRIBUTING.adoc[here]. 🎯 🎯
[quote, The Starknet Community]
____
*Unleash Your Passion to Perfect StarkNetBook*
StarkNetBook is a work in progress, and your passion, expertise, and unique insights can help transform it into something truly exceptional. Don't be afraid to challenge the status quo or break the Book! Together, we can create an invaluable resource that empowers countless others. :emoji-rocket: :emoji-sparkles:
Embrace the excitement of contributing to something bigger than ourselves. If you see room for improvement, seize the opportunity! Check out our https://github.com/starknet-edu/starknetbook/blob/main/CONTRIBUTING.adoc[guidelines] and join our vibrant community. Let's fearlessly build Starknet!
____
49 changes: 49 additions & 0 deletions chapters/modules/chapter_2/pages/external.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
[id="external"]

= External Functions in Cairo

External functions are functions that can be called by other contracts or externally by users through a transaction on the blockchain. They can change the contract's state, and therefore, require gas fees for execution. This means that we can write to the contract's storage using the `write` function.

In Cairo, external functions are defined using the `#[external]` attribute. In Solidity, you would use the `public` or `external` keyword to define a similar type of function.

In the Vote contract, there is only one external function: `vote`. Let's examine it in detail:

[source,rust]
----
// @dev Submit a vote (0 for No and 1 for Yes)
// @param vote (u8): vote value, 0 for No and 1 for Yes
// @return () : updates the storage with the vote count and marks the voter as not allowed to vote again
#[external]
fn vote(vote: u8) {
// Check if the vote is valid (0 or 1)
assert(vote == 0_u8 | vote == 1_u8, 'VOTE_0_OR_1');
// Know if a voter has already voted and continue if they have not voted
let caller : ContractAddress = get_caller_address();
assert_allowed(caller);
// Mark that the voter has already voted and update in the storage
can_vote::write(caller, false);
// Update the vote count in the storage depending on the vote value (0 or 1)
if (vote == 0_u8) {
no_votes::write(no_votes::read() + 1_u8);
}
if (vote == 1_u8) {
yes_votes::write(yes_votes::read() + 1_u8);
}
}
----

The `vote` function is an external function that allows users to submit their vote (0 for No and 1 for Yes) to the contract. It takes a `u8` value as input, checks if the value is valid (0 or 1), and updates the storage accordingly.

== Contributing

[quote, The Starknet Community]
____
*Unleash Your Passion to Perfect StarkNetBook*
StarkNetBook is a work in progress, and your passion, expertise, and unique insights can help transform it into something truly exceptional. Don't be afraid to challenge the status quo or break the Book! Together, we can create an invaluable resource that empowers countless others. :emoji-rocket: :emoji-sparkles:
Embrace the excitement of contributing to something bigger than ourselves. If you see room for improvement, seize the opportunity! Check out our https://github.com/starknet-edu/starknetbook/blob/main/CONTRIBUTING.adoc[guidelines] and join our vibrant community. Let's fearlessly build Starknet!
____
74 changes: 74 additions & 0 deletions chapters/modules/chapter_2/pages/functions.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
[id="functions"]

= Functions and Modules in Cairo

In Cairo, functions and modules are used to structure the code and define reusable pieces of logic. They are similar to Solidity functions and contracts, but there are some differences in their implementation and usage.

== Functions in Cairo

Cairo functions are defined using the `fn` keyword. Functions can have different attributes depending on their purpose, such as `#[constructor]`, `#[view]`, or `#[external]`. Functions can accept arguments, return values, and interact with the contract's storage.

An example of a Cairo function:

[source,rust]
----
#[view]
fn get_vote_status() -> (u8, u8) {
let n_yes = yes_votes::read();
let n_no = no_votes::read();
return (n_yes, n_no);
}
----

This function is a view function that returns the current number of yes and no votes.

[NOTE]
====
Function visibility (public, external, internal, or private) is not explicitly specified in Cairo. Instead, functions are considered internal by default unless they are marked with the `#[view]` or `#[external]` attributes (we will review them in the next section). In Solidity, you specify the visibility using keywords (public, external, internal, or private).
====

== Modules in Cairo

Cairo modules are used to group related functionality under a namespace. A module is defined using the `mod` keyword, followed by the module name and a block of code containing functions and other declarations. Modules can import other modules and use their functionality.

An example of a Cairo module:

[source,rust]
----
#[contract]
mod Vote {
// Core Library Imports
use starknet::ContractAddress;
use starknet::get_caller_address;
use array::ArrayTrait;
// Other declarations and functions
}
----

In this example, the `Vote` module imports other modules like `starknet` and `array` and defines a contract with its storage, functions, and other declarations.

== Comparison with Solidity

1. *Functions*:
a. *Declaration*: Cairo functions are declared with the `fn` keyword, while Solidity functions use the `function` keyword.
b. *Attributes*: Cairo functions use attributes like `#[constructor]`, `#[view]`, and `#[external]` to indicate their purpose. In Solidity, keywords like `constructor`, `view`, and `public` are used instead.
c. *Return values*: In Cairo, return values are declared using the `->` syntax, while Solidity uses the `returns` keyword.

2. *Modules*:
a. *Declaration*: Cairo modules are declared with the `mod` keyword, while Solidity uses the `contract` keyword to define a contract.
b. *Imports*: Cairo modules can import other modules using the `use` keyword. In Solidity, the `import` keyword is used to include external contracts or libraries.
c. *Namespaces*: Cairo modules serve as namespaces for related functionality. In Solidity, contracts themselves act as namespaces for their functions and variables.


== Contributing

[quote, The Starknet Community]
____
*Unleash Your Passion to Perfect StarkNetBook*
StarkNetBook is a work in progress, and your passion, expertise, and unique insights can help transform it into something truly exceptional. Don't be afraid to challenge the status quo or break the Book! Together, we can create an invaluable resource that empowers countless others. :emoji-rocket: :emoji-sparkles:
Embrace the excitement of contributing to something bigger than ourselves. If you see room for improvement, seize the opportunity! Check out our https://github.com/starknet-edu/starknetbook/blob/main/CONTRIBUTING.adoc[guidelines] and join our vibrant community. Let's fearlessly build Starknet!
____
57 changes: 57 additions & 0 deletions chapters/modules/chapter_2/pages/getter.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
[id="getter"]

= Getters Functions (View Functions) in Cairo

Getter functions, also known as view functions, are read-only functions that allow you to access data from the contract's storage without modifying it. They can be called by other contracts or externally, and they do not require gas fees as they do not alter the contract's state.

In Cairo, getter functions are defined using the `#[view]` attribute. In Solidity, you would use the `view` keyword to define a similar type of function.

Here's an overview of the getter functions in the Vote contract:

1. `get_vote_status`: Returns the current number of yes and no votes.
2. `voter_can_vote`: Returns whether a given voter is allowed to vote or not.
3. `is_voter_registered`: Returns whether a given address is a registered voter or not.

Let's examine each getter function in detail:

[source,rust]
----
// @dev Return the number of yes and no votes
// @return status (u8, u8): current status of the vote (yes votes, no votes)
#[view]
fn get_vote_status() -> (u8, u8) {
// Read the number of yes votes and no votes from storage
let n_yes = yes_votes::read();
let n_no = no_votes::read();
// Return the current voting status
return (n_yes, n_no);
}
----

The `get_vote_status` function reads the `yes_votes` and `no_votes` values from the storage and returns them as a tuple of two unsigned 8-bit integers. In Solidity, you would return a tuple of `uint8` values.

[source,rust]
----
// @dev Returns if a voter can vote or not
// @param user_address (ContractAddress): address of the voter
// @return status (bool): true if the voter can vote, false otherwise
#[view]
fn voter_can_vote(user_address: ContractAddress) -> bool {
// Read the voting status of the user from storage
can_vote::read(user_address)
}
----

The `voter_can_vote` function takes a `ContractAddress` as input and reads the voting status of the user from the `can_vote` mapping in the storage. It returns a `bool` value indicating whether the voter is allowed to vote or not. In Solidity, you would use a `mapping` with an `address` key type to store a similar data structure. The `is_voter_registered` function is similar to the voter_can_vote function, but it returns a `bool` value indicating whether the address is a registered voter or not.

== Contributing

[quote, The Starknet Community]
____
*Unleash Your Passion to Perfect StarkNetBook*
StarkNetBook is a work in progress, and your passion, expertise, and unique insights can help transform it into something truly exceptional. Don't be afraid to challenge the status quo or break the Book! Together, we can create an invaluable resource that empowers countless others. :emoji-rocket: :emoji-sparkles:
Embrace the excitement of contributing to something bigger than ourselves. If you see room for improvement, seize the opportunity! Check out our https://github.com/starknet-edu/starknetbook/blob/main/CONTRIBUTING.adoc[guidelines] and join our vibrant community. Let's fearlessly build Starknet!
____
Loading

0 comments on commit b473556

Please sign in to comment.