description: Learn how to write a simple smart contract in the Clarity language.
description: Learn how to write a simple counter in Clarity.
experience: intermediate
experience: beginner
duration: 30 minutes
duration: 20 minutes
tags:
tags:
- tutorial
- tutorial
images:
images:
@ -12,148 +12,120 @@ images:
## Introduction
## Introduction
In this tutorial, you learn how to implement a smart contract that stores and manipulates an integer value on the Stacks 2.0 blockchain. By the end of this tutorial, you will ...
This tutorial introduces variables in Clarity, and demonstrates how to interact with them through a simple incrementing
and decrementing counter. This tutorial builds on concepts introduced in the [hello world tutorial][] and continues to
exercise [Clarinet][] as a local development environment.
- Have experienced test-driven development with Clarity
In this tutorial you will:
- Understand more Clarity language design principles
- Have a working Clarity counter smart contract
## Prerequisites
- Create a new Clarinet project
- Add a new Clarity contract to the project
=> Before you get started, you should complete the [Hello World tutorial](/write-smart-contracts/hello-world-tutorial).
- Populate the contract with a variable and read variable function
- Populate the contract with an increment and a decrement function
### Check the Stacks 2.0 status
- Execute the functions in a local, simulated blockchain
- Optionally, deploy and test the contract on the testnet blockchain
The Stacks 2.0 blockchain is currently in development and could experience resets and downtimes. To make sure you're not
running into any challenges related to the status of the network, please open up the [Status Checker](https://stacks-status.com/)
and confirm that all systems are operational. If some systems seem to have issues, it is best to wait until they are back up before you proceed with the next steps.
## Step 1: Downloading counter starter project
In this step, you initialize a starter project with additional counter tutorial files:
Using your terminal, run the following command to create a new folder and initialize a new project:
```bash
## Prerequisites
# create and go to new `counter` project folder
mkdir counter; cd counter
npm init clarity-starter
```
You will be asked to select a project template. Press down with your arrow keys to choose `Counter` and hit **ENTER**:
```bash
For this tutorial, you should have a local installation of Clarinet. Refer to [Installing Clarinet][] for instructions
? Select a project template: (Use arrow keys)
on how to set up your local environment. You should also have a text editor or IDE to edit the Clarity smart contract.
Hello World
❯ Counter
```
Finally, the project dependencies are installed and your project is ready for development. Because you already completed the [Hello World tutorial](/write-smart-contracts/hello-world-tutorial), the project structure is familiar to you. The main difference is that we have additional tests for a new counter smart contract.
### Optional prerequisites
## Step 2: Running tests
While this tutorial primarily focuses on local smart contract development, you may wish to deploy your contract to
a live blockchain. For simplicity, contract deployment is performed using the [testnet sandbox][]. If you wish to
complete the optional deployment step, you should have the [Stacks Web Wallet][] installed, and you should request
testnet STX tokens from the [testnet faucet][] on the testnet explorer. Note that requesting testnet STX from the faucet
can take up to 15 minutes, so you may wish to request the tokens before beginning the tutorial.
Smart contracts are often developed in a test-driven approach. This not only improves code quality, but also removes the need to push every iteration to the blockchain before executing it. We will do the same in this project. Now, let's run the tests and review the results:
## Step 1: create a new project
Still in the project root directory, run the following command:
With Clarinet installed locally, open a new terminal window and create a new Clarinet project with the command:
```bash
```sh
npm test
clarinet new clarity-counter && cd clarity-counter
```
```
You should see the following response:
This command creates a new directory for your smart contract project, populated with boilerplate configuration and
testing files. Creating a new project only creates the Clarinet configuration, in the next step you can add a contract
```bash
to the project.
counter contract test suite
✓ should have a valid syntax
deploying an instance of the contract
1) should start at zero
2) should increment
3) should decrement
1 passing (734ms)
## Step 2: create a new contract
3 failing
... # error details
From the `clarity-counter` directory, create a new Clarity contract with the command:
npm ERR. Test failed. See above for more details.
```sh
clarinet contract new counter
```
```
It looks like we see some failed tests. That is on purpose - we will implement the new smart contract in the next steps. After every step in this tutorial, we will rerun the tests to ensure we're on the right track.
This command adds a new `counter.clar` file in the `contracts` directory, and adds a `counter_test.ts` file to
the `test` directory. This tutorial ignores the test file, but for production contracts, you can create [unit tests][]
using it.
## Step 3: Developing a smart contract
## Step 3: define variables
Let's get familiar with the tests to understand what the new smart contract should look like
Open the `contracts/counter.clar` file in a text editor or IDE. Delete the boilerplate comments, for the purpose of
this tutorial they're not necessary.
1. In your editor, take a quick look at the test file associated with the counter smart contract: `test/counter.ts`
In this step, you'll add a variable to the contract, and define a read-only function to output the value of that
variable.
```bash
Start by defining the variable on the first line
cat test/counter.ts
```
You will see a [Mocha](https://mochajs.org/) test suite. This file describes the tests for the counter smart contract.
```clarity
Notice how the smart contract is instantiated on line 8 of file `counter.ts`
That tells us that the new smart contract is named `counter` and that it should be found in the following file:
The [`define-data-var`][] statement initializes a new integer variable named `counter` and sets the initial value to
`contracts/counter.clar`. Note that the `contracts` folder is assumed as the base folder and that every Clarity file
`0`. It's important to note that all definition statements in Clarity need to be at the top of the file.
has the suffix `.clar`.
The file was already created during the project setup.
The `counter` variable is stored in the data space associated with the smart contract. The variable is persisted and
acts as a global shared state.
2. Using your editor, open `contracts/counter.clar`. You will notice the file already includes some content:
To provide access to the `counter` variable from outside the contract that it's defined in, you should declare a
`read-only` function to get the value. Add this function below the variable definition:
```clarity
```clarity
;; define counter variable
;; increment method
;; decrement method
;; counter getter
;; counter getter
(define-read-only (get-counter)
(ok (var-get counter)))
```
```
What you see are four one-line comments. In Clarity, a comment line is started with `;;`. As you can see, the
The [`var-get`][] statement looks for a variable in the contract's data space and returns it.
comments indicate the structure of the smart contract we are going to implement.
Let's declare a counter variable and define a read-only getter method:
Your contract code should now look like this:
```clarity
```clarity
;; define counter variable
;; define counter variable
(define-data-var counter int 0)
(define-data-var counter int 0)
...
;; counter getter
;; counter getter
(define-read-only (get-counter)
(define-read-only (get-counter)
(ok (var-get counter)))
(ok (var-get counter)))
```
```
The [`define-data-var`](/references/language-functions#define-data-var) statement initializes a
At this point, you can check your contract code to ensure the syntax is correct. In the `clarity-counter` directory in
new integer variable named `counter` and sets the value to `0`. It is important to note that all definition statements
your terminal, use the command:
in Clarity need to be at the top of the file.
The `counter` variable is stored in the data space associated with the smart contract. The variable is persisted and
```sh
acts as the global shared state.
clarinet check
```
To provide access to the `counter` variable from outside of the current smart contract, we need to declare a read-only function to get it. The last lines of the code add a read-only `get-counter` function. The [`var-get`](/references/language-functions#var-get) statement looks for a variable in the contract's data space and returns it.
With that, you are ready to rerun the tests
3. Run the tests and review the results:
If there are no errors, the command returns no output. If there are errors, verify that your contract is exactly as
listed in the preceding section. You can also use the [`clarinet console`][] to interact with the `get-counter`
function:
```bash
```clarity
npm test
(contract-call? .counter get-counter)
```
```
You should now only see 2 failing tests. `should start at zero` is passing, and you successfully build your first part of the contract. Congrats.
The console should return `(ok 0)`.
However, we don't stop here. Let's implement increment and decrement functions.
## Step 4: define counter functions
4. Add the following lines to the `counter.clar` file (below the increment method comment) and take a few seconds to review them:
In this step, you'll add functions to increment and decrement the counter variable. Add the `increment` function to
the contract after the counter getter:
```clarity
```clarity
;; increment method
;; increment method
@ -163,63 +135,123 @@ Let's get familiar with the tests to understand what the new smart contract shou
(ok (var-get counter))))
(ok (var-get counter))))
```
```
First, the [`begin`](/references/language-functions#begin) statement evaluates multiple expressions and returns the value of the last one. In this case, it is used to set a new value and return the new value.
The [`begin`][] statement evaluates multiple expressions and returns the value of the last on. In this case, it
evaluates an expression to set a new value for the `counter` variable, and then returns the new value.
The first expression in the `begin` statement is the [`var-set`][] expression, which sets a new value for the counter
variable. The new value is constructed using the [`+`] (add) statement. This statement takes a number of integer
arguments and returns the sum of the integers. Along with add, Clarity provides statements to subtract, multiply, and
divide integers. Find more details in the [Clarity language reference][].
Next, a [`var-set`](/references/language-functions#var-set) is used to set a new value for the `counter` variable. The new value is constructed using the [`+`](/references/language-functions#-add) (add) statement. This statement takes a number of integers and returns the result. Along with add, Clarity provides statements to subtract, multiply, and divide integers. Find more details in the [Clarity language reference](/references/language-functions).
Next, implement a new public function `decrement` to subtract `1` from the counter variable:
5. Next, implement a new public function `decrement` to subtract `1` from the `counter` variable. You should have all knowledge needed to succeed at this
```clarity
;; decrement method
(define-public (decrement)
(begin
(var-set counter (- (var-get counter) 1))
(ok (var-get counter))))
```
Here is the final contract:
At this point the contract is complete. The full `counter.clar` file should look like this:
```clarity
```clarity
;; define counter variable
(define-data-var counter int 0)
(define-data-var counter int 0)
;; counter getter
(define-read-only (get-counter)
(define-read-only (get-counter)
(ok (var-get counter)))
(ok (var-get counter)))
;; increment method
(define-public (increment)
(define-public (increment)
(begin
(begin
(var-set counter (+ (var-get counter) 1))
(var-set counter (+ (var-get counter) 1))
(ok (var-get counter))))
(ok (var-get counter))))
;; decrement method
(define-public (decrement)
(define-public (decrement)
(begin
(begin
(var-set counter (- (var-get counter) 1))
(var-set counter (- (var-get counter) 1))
(ok (var-get counter))))
(ok (var-get counter))))
```
```
Done? Great. Run the tests and make sure all of them are passing. You are looking for 4 passed tests:
## Step 5: interact with the contract on the Clarinet console
```bash
counter contract test suite
✓ should have a valid syntax (39ms)
deploying an instance of the contract
✓ should start at zero
✓ should increment (133ms)
✓ should decrement (177ms)
4 passing (586ms)
```
## Step 4: Deploy and call the contract
Your new smart contract is ready to be deployed to the Stacks 2.0 blockchain. You should be familiar with the steps
Run `clarinet check` again to verify that the syntax in your contract is correct. If there are no errors, the command
from the ["Hello, World" tutorial](/write-smart-contracts/hello-world-tutorial#deploy-the-contract).
returns no output. Use the following command to launch the local console:
As soon as you successfully deploy your contract, you can play around with the contract and verify the functionality by
```sh
calling all public methods you implemented. Here's a suggested order:
clarinet console
```
- Call the `get-counter` method. It should return `0`
You'll use the console to interact with the functions in your contract. Call the `increment` function to increment the
- Call the `increment` method and let the transaction complete
counter in the console:
- Call the `get-counter` method. It should return `1`
- Call the `decrement` method and let the transaction complete
- Call the `get-counter` method. It should return `0`
-> As you can see, read-only function calls don't require a transaction to complete. This is because the method doesn't require a state change.
```clarity
(contract-call? .counter increment)
```
=> Congratulations. You just implemented, deployed, and called your own Clarity smart contract.
The console should return (ok 1). Try calling the `decrement` function to decrement the counter back to 0.
With the completion of this tutorial, you:
```clarity
(contract-call? .counter decrement)
```
- Experienced test-driven development with Clarity
-> You have now learned the basics of working with variables in Clarity, and developed further practice with the
- Understood more Clarity language design principles
Clarinet development tool. You may wish to optionally deploy the contract to the testnet, described in the next and
- Developed a working Clarity counter smart contract and called its public methods
final step.
## Optional: deploy and test the contract on the testnet
For this tutorial, you'll use the [testnet sandbox][] to deploy your smart contract. Make sure you have connected your
[Stacks web wallet][] to the sandbox using the **Connect wallet** button, then copy and paste your smart contract into
the Clarity code editor on the **Write & Deploy** page. Edit the contract name or use the randomly generated name