Skip to main content

Counter

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.

In this tutorial you will:

  • Create a new Clarinet project
  • Add a new Clarity contract to the project
  • Populate the contract with a variable and read variable function
  • Populate the contract with an increment and a decrement function
  • Execute the functions in a local, simulated blockchain
  • Optionally, deploy and test the contract on the testnet blockchain

Prerequisites

For this tutorial, you should have a local installation of Clarinet. Refer to Installing Clarinet for instructions on how to set up your local environment. You should also have a text editor or IDE to edit the Clarity smart contract.

If you are using Visual Studio Code, you may want to install the Clarity Visual Studio Code plugin.

Optional prerequisites

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 Leather 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.

Step 1: create a new project

With Clarinet installed locally, open a new terminal window and create a new Clarinet project with the command:

clarinet new clarity-counter && cd clarity-counter

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 to the project.

Step 2: create a new contract

From the clarity-counter directory, create a new Clarity contract with the command:

clarinet contract new counter

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: define variables

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.

In this step, you'll add a variable to the contract, and define a read-only function to output the value of that variable.

Start by defining the variable on the first line

;; define counter variable
(define-data-var counter int 0)

The define-data-var statement initializes a new integer variable named counter and sets the initial value to 0. It's important to note that all definition statements 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

acts as a global shared state.

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:

;; counter getter
(define-read-only (get-counter)
(ok (var-get counter)))

The var-get statement looks for a variable in the contract's data space and returns it.

Your contract code should now look like this:

;; define counter variable
(define-data-var counter int 0)

;; counter getter
(define-read-only (get-counter)
(ok (var-get counter)))

At this point, you can check your contract code to ensure the syntax is correct. In the clarity-counter directory in your terminal, use the command:

clarinet check

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:

(contract-call? .counter get-counter)

The console should return (ok 0).

note

Changes to your contract will not be loaded into the Clarinet console until it is restarted. Close the console with Ctrl + C before proceding to the next step.

Step 4: define counter functions

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:

;; increment method
(define-public (increment)
(begin
(var-set counter (+ (var-get counter) 1))
(ok (var-get counter))))

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, implement a new public function decrement to subtract 1 from the counter variable:

;; decrement method
(define-public (decrement)
(begin
(var-set counter (- (var-get counter) 1))
(ok (var-get counter))))

At this point the contract is complete. The full counter.clar file should look like this:

;; define counter variable
(define-data-var counter int 0)

;; counter getter
(define-read-only (get-counter)
(ok (var-get counter)))

;; increment method
(define-public (increment)
(begin
(var-set counter (+ (var-get counter) 1))
(ok (var-get counter))))

;; decrement method
(define-public (decrement)
(begin
(var-set counter (- (var-get counter) 1))
(ok (var-get counter))))

Step 5: interact with the contract on the Clarinet console

Run clarinet check again to verify that the syntax in your contract is correct. If there are no errors, the command returns no output. Use the following command to launch the local console:

clarinet console

You'll use the console to interact with the functions in your contract. Call the increment function to increment the counter in the console:

(contract-call? .counter increment)

The console should return (ok 1). Try calling the decrement function to decrement the counter back to 0.

(contract-call? .counter decrement)

You have now learned the basics of working with variables in Clarity, and developed further practice with the Clarinet development tool. You may wish to optionally deploy the contract to the testnet, described in the next and 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 Leather 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 provided to you.

Counter testnet sandbox

Click Deploy to deploy the contract to the blockchain. This will display the Leather wallet window with information about the transaction. Verify that the transaction looks correct, and the network is set to Testnet, and click Confirm.

The contract is added to the miners mempool, and included in the next block of the blockchain. This process can take up to 15 minutes to complete. You can review it on the transactions page of the explorer or in the activity field of your web wallet.

When your contract is confirmed, navigate to the call a contract page of the sandbox, and search for your contract. Enter your wallet address in the top field, you can copy this address by clicking the Leather wallet icon and clicking the Copy address button. Enter the contract name in the bottom field, in this case counter. Click Get Contract to view the contract.

Click the increment function in the function summary, then click Call Function to perform the function call in the sandbox. This will display the Leather wallet with information about the transaction. Verify the information, then click Confirm to execute the function call.

The function call is added to the miners mempool, and is executed in the next block of the blockchain. This process can take up to 15 minutes to complete. You can review it on the transactions page of the explorer or in the activity field of your web wallet.

When the transaction is complete, you can access the transaction summary page from the activity panel in your web wallet. The transaction summary page displays the output of the function.

Try calling the other public functions from the call a contract page.

You have now learned one method of deploying and interacting with smart contracts on Stacks. You have also learned the strengths of performing local development without having to wait for block times.