In this workshop, you will learn how to create a simple Starknet smart contract, implement public functions, events, and access external contracts.
After completing each step, run the associated script to verify it has been implemented correctly.
Use the Cairo book and the Starknet docs as a reference.
- Clone this repository
- Create a new file called
counter.cairo
inside thesrc
folder - Copy the following code into the file
#[starknet::contract]
mod Counter {
#[storage]
struct Storage {}
}
Note: You'll be working on the
counter.cairo
file to complete the requirements of each step. The fileprev_solution.cairo
will show up in future steps as a way to catch up with the workshop if you fall behind. Don't modify that file.
The next setup steps will depend on wether you prefer using Docker to manage global dependencies or not.
- Install Scarb 2.5.1 (instructions)
- Install Starknet Foundry 0.16.0 (instructions)
- Install the Cairo 1.0 extension for VSCode (marketplace)
- Run the tests to verify the project is setup correctly
$ scarb test
- Make sure Docker is installed and running
- Install the Dev Containers extension for VSCode (marketplace)
- Launch an instance of VSCode inside of the container by going to View -> Command Palette -> Dev Containers: Rebuild and Reopen in Container
- Open VSCode's integrated terminal and run the tests to verify the project is setup correctly
$ scarb test
Note: All the commands shown from this point on will assume that you are using the integrated terminal of a VSCode instance running inside the container. If you want to run the tests on a different terminal you'll need to use the command
docker compose run test
.
Checkout the step1
branch to enable the verification tests for this section.
$ git checkout -b step1 origin/step1
In this step, you will need to do the following:
- Store a variable named
counter
asu32
type in theStorage
struct. - Implement the constructor function that initializes the
counter
variable with a given input value. - Implement a public function named
get_counter()
which returns the value of thecounter
variable.
- The
get_counter()
function must be within the contract's interface namedICounter
.
Note: Any other given name to the contract's interface would break the test, be sure to have to correct name!
When completed, execute the test suite to verify you've met all the requirements for this section.
$ scarb test
- Storage variables are the most common way to interact with your contract storage. You can read more about it in Chapter 12.3.1 - Contract Storage.
- The constructor function is a special type of function that runs only once. You can read more about it in Chapter 12.3.2 - Constructor Function.
- To create a contract interface, you will need to define a trait with the name
ICounter
(otherwise the tests will fail) and mark the trait with the[starknet::interface]
attribute. You can read more about it in Chapter 12.5 Interfaces. - The
get_counter()
function should only be able to read the state of the contract and not modify it. You can read more about it in Chapter 12.3.2 - View functions.
Checkout the step2
branch to enable the verification tests for this section.
$ git checkout -b step2 origin/step2
If you fell behind, the file prev_solution.cairo
contains the solution to the previous step.
Implement a function called increase_counter()
that can increment the current value of the counter
by 1
each time it is invoked.
When completed, execute the test suite to verify you've met all the requirements for this section.
$ scarb test
- The
increase_counter()
function should be able to modify the state of the contract (also called an external function) and update thecounter
value within theStorage
. You can read more about it in Chapter 12.3.2 - External Functions.
Checkout the step3
branch to enable the verification tests for this section.
$ git checkout -b step3 origin/step3
If you fell behind, the file prev_solution.cairo
contains the solution to the previous step.
In this step, you will need to do the following:
- Import the
KillSwitch
contract interface into your project. - Store a variable named
kill_switch
as typeIKillSwitchDispatcher
in theStorage
. - Update the constructor function to receive an additional input variable with the type
ContractAddress
. - Update the constructor function to initialize the
kill_switch
variable with the newly added input variable. Note that you need to use theIKillSwitchDispatcher
which expects aContractAddress
as its type.
Note: Analyze the
KillSwitch
code to understand the interface and the contract structure from here. This is already added as a dependency in yourScarb.toml
file.
When completed, execute the test suite to verify you've met all the requirements for this section.
$ scarb test
- You need to import
Dispatcher
andDispatcherTrait
of the KillSwitch contract. These dispatchers are automatically created and exported by the compiler. More information about Contract Dispatcher can be found in Chapter 12.5.2 - Contract Dispatcher. - In the constructor, you can update the variable
kill_switch
with theIKillSwitchDispatcher { contract_address: ??? }
, which expects the address of the external contract.
Note: If you want to deploy the
Counter
contract, you can use the following deployedKillSwitch
contract address.Goerli
Contract Address:
0x033b2c899fd8f89e3e1d5b69c4d495f1018a1dbb8c19b18795c2e16b078da34d
Checkout the step4
branch to enable the verification tests for this section.
$ git checkout -b step4 origin/step4
If you fell behind, the file prev_solution.cairo
contains the solution to the previous step.
Implement the KillSwitch
mechanism in the increase_counter()
by calling the is_active()
function from the KillSwitch
contract.
- If the function
is_active()
from the KillSwitch contract returnstrue
, then allow theincrease_counter()
to increment the value. - If the function
is_active()
from the KillSwitch contract returnsfalse
, then return without incrementing the value.
When completed, execute the test suite to verify you've met all the requirements for this section.
$ scarb test
- You can access the
is_active()
function from yourkill_switch
variable. Use this to create the logic in theincrease_counter()
function.
Checkout the step5
branch to enable the verification tests for this section.
$ git checkout -b step5 origin/step5
If you fell behind, the file prev_solution.cairo
contains the solution to the previous step.
In this step, you will need to do the following:
- Implement an event named
CounterIncreased
which emits the current value of thecounter
. - Emit this event when the
counter
variable has been successfully incremented.
When completed, execute the test suite to verify you've met all the requirements for this section.
$ scarb test
- Events are custom data structures that are emitted by a contract. More information about Events can be found in Chapter 12.3.3 - Contract Events.
Checkout the step6
branch to enable the verification tests for this section.
$ git checkout -b step6 origin/step6
If you fell behind, the file prev_solution.cairo
contains the solution to the previous step.
Check that you have correctly created an account contract for Starknet by running the full test suite:
$ scarb test
If the test suite passes, congratulations, you have created your first Counter Smart Contract on Starknet.