Browse Source

Updating Clarity docs and tutorials (#541)

* [WIP] Updating tutorial

* Replace old Docker steps with ClarityJS SDK steps

* Removing block properties section

* fixing formatting

* Adding second tutorial, updating first

* Adding thirs tutorial boilerplate

* Fixes based on feedback

* Update overview

* Adding use cases, fixing links, update folder names

* Fixes based on feedback

* form > from

* title fixes

* Add public function explanation and fix language

* language updates

* updates based on feedback
feat/clarity-updates
Alexander Graebe 5 years ago
committed by GitHub
parent
commit
3cf39fe48e
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 45
      _core/smart/clarityRef.md
  2. 2
      _core/smart/functions.md
  3. 129
      _core/smart/overview.md
  4. 2
      _core/smart/principals.md
  5. 10
      _core/smart/sdk-quickstart.md
  6. 169
      _core/smart/tutorial-counter.md
  7. 328
      _core/smart/tutorial.md
  8. 23
      _data/navigation_core.yml
  9. 26
      _data/navigation_home.yml
  10. 7
      _sass/syntax-highlighting/github.scss

45
_core/smart/clarityRef.md

@ -3,50 +3,13 @@ layout: core
description: "Blockstack smart contracting language"
permalink: /:collection/:path.html
---
# Clarity language reference
# Language Reference
This file contains the reference for the Clarity language.
* TOC
{:toc}
## Block Properties
The `get-block-info` function fetches property details for a block at a specified block height. For example:
```cl
(get-block-info time 10) ;; Returns 1557860301
```
Because the Clarity language is in pre-release, the block properties that are fetched are simulated properties from a SQLite database. The available property names are:
<table class="uk-table">
<tr>
<th>Property</th>
<th>Definition</th>
</tr>
<tr>
<td><code>header-hash</code></td>
<td>A 32-byte buffer containing the block hash.</td>
</tr>
<tr>
<td><code>burnchain-header-hash</code></td>
<td>A 32-byte buffer that contains the hash from the proof of burn.</td>
</tr>
<tr>
<td><code>vrf-seed</code></td>
<td>A 32-byte buffer containing the Verifiable Random Function (VRF) seed value used for the block.</td>
</tr>
<tr>
<td><code>time</code></td>
<td>An integer value containing that roughly corresponds to when the block was mined. This is a Unix epoch timestamp in seconds. </td>
</tr>
</table>
{% include warning.html content="The <code>time</code> does not increase monotonically with each block. Block times are accurate only to within two hours. See <a href='https://github.com/bitcoin/bips/blob/master/bip-0113.mediawiki' target='_blank'>BIP113</a> for more information." %}
## Supported types
This section lists the types available to smart contracts. The only atomic types supported by the Clarity are booleans, integers, fixed length buffers, and principals.
@ -55,6 +18,12 @@ This section lists the types available to smart contracts. The only atomic types
The integer type in the Clarity language is a 16-byte signed integer, which allows it to specify the maximum amount of microstacks spendable in a single Stacks transfer. The special `BlockHeightInt` you can obtain with the `get-block-info` function.
### Uint type
The unsigned integer type (`uint`) in the Clarity language is a 16-byte unsigned integer. Using the unsigned type can ensure that any value underflows (negative numbers) will cause a transaction to be aborted.
Anywhere a developer wishes to use a literal unsigned integer (for example, incrementing or decrementing an input by a constant) the integer literal should use the `u` prefix, e.g., `u123`.
### Bool type
Supports values of `'true` or `'false`.

2
_core/smart/functions.md

@ -3,7 +3,7 @@ layout: core
description: "Blockstack smart contracting language"
permalink: /:collection/:path.html
---
# Define functions and data maps
# Defining Functions and Maps
{:.no_toc}
Clarity includes _defines_ and native functions for creating user-defined functions.

129
_core/smart/overview.md

@ -1,131 +1,45 @@
---
layout: core
description: "Blockstack smart contracting language"
description: "Blockstack Clarity: Introduction"
permalink: /:collection/:path.html
---
# Welcome to Clarity
# Introduction to Clarity
{:.no_toc}
Clarity is Blockstack's smart contracting language for use with the Stacks blockchain. Clarity supports programmatic control over digital assets within the Stacks blockchain (for example, BNS names, Stacks tokens, and so forth). This section discusses the following topics:
Clarity is a smart contracting language for use with the Stacks 2.0 blockchain. It supports programmatic control over digital assets.
* TOC
{:toc}
<div class="uk-card uk-card-default uk-card-body">
<h5>Clarity is in pre-release</h5>
<p>Clarity, its accompanying toolset, and the SDK are in pre-release. If you encounter issues with or have feature requests regarding Clarity, please create an issue on the <a href='https://github.com/blockstack/blockstack-core/issues' target='_blank'>blockstack/blockstack-core</a> repository. To read previous or join ongoing discussions about smart contracts in general and Clarity in particular, visit the <strong><a href='https://forum.blockstack.org/c/clarity' target='_blank'>Smart Contracts</a></strong> topic in the Blockstack Forum.
</p>
</div>
## Smart contracts
## Who should use smart contracts?
You can use Clarity to write standalone contracts or to write contracts that are part of decentralized applications (DApps) you write with the blockstack.js library. Smart contracts allow two parties to exchange anything of value (money, property, shares), in an automated, auditable, and secure way _without the services of a middleman_. Nick Szabo introduced the canonical metaphor for smart contracts, a vending machine.
Smart contracts encode and enforce the rules for curating this data, and are often used to ensure that users can exchange valuable data in an automated and secure way. For example, a smart contract could allow anyone to add a new movie to a movie catalog, but require that someone first pay for a decryption key before anyone can view it. To do this, the smart contract could be written such that the movie creator had to publicly disclose the decryption key in order to receive payment. Such a system would allow movie creators to make money by adding movies to the movie catalog that people want to watch.
In Nick Szabo's metaphor, the vending machine is the smart contract. The buyer and machine owner are the two parties. A vending machine executes a set of hard-coded actions when the buyer engages with it. The machine displays the items and their prices. A buyer enters money into the machine which determines if the amount fails to mee, meets, or exceeds an item's price. Based on the amount, the machine asks for more money, dispenses an item, or dispenses and item and change.
Because smart contracts run on top of a blockchain, anyone can query them, and anyone can submit transactions to run their code. The blockchain stores the history of all accepted transactions, so anyone can audit the blockchain in order to independently verify that an app's global shared state has been managed correctly according to the smart contract's rules.
Not every application requires smart contracts. If you are not sure or are new to smart contracts concepts, you should read <a href="https://blockgeeks.com/guides/smart-contracts/" target="_blank">a good general explanation of smart contracts</a> before working with Clarity.
## Use cases
## Language and program design
Not every decentralized application requires smart contracts, but Clarity unlocks interesting capabilities for decentralized applications. Examples of use cases include, but are not limited to:
Clarity differs from most other smart contract languages in two essential ways:
* Access control (e.g. pay to access)
* Non-fungible and fungible tokens
* Business model templates (e.g. subscriptions)
* App-specific blockchains
* Decentralized Autonomous Organizations
* The language is not intended to be compiled.
* The language is not Turing complete.
## Language design
These differences allow for static analysis of programs to determine properties like runtime cost and data usage.
Clarity is a [list processing (LISP) language](https://en.wikipedia.org/wiki/Lisp_(programming_language)) and differs from most other smart contract languages in two essential ways:
A Clarity smart contract is composed of two parts &mdash; a data-space and a set of functions. Only the associated smart contract may modify its corresponding data-space on the blockchain. Functions are private unless they are defined as public functions. Users call smart contracts' public functions by broadcasting a transaction on the blockchain which invokes the public function.
* The language is interpreted and broadcasted on the blockchain as is (not compiled)
* The language is decidable (not Turing complete)
Contracts can also call public functions from other smart contracts. The ability to do a static analysis of a smart contract allows a user to determine dependency between contracts.
Using an interpreted language ensures that the code that executes is human-readable, and is auditable by users. The fact that Clarity is a decidable language means that users can determine the set of reachable code from any function they want to call.
## The coding environment
A Clarity smart contract is composed of two parts &mdash; a data-space and a set of functions. Only the associated smart contract may modify its corresponding data-space on the blockchain. Functions may be private and thus callable only from within the smart contract, or public and thus callable from other contracts. Users call smart contracts' public functions by broadcasting a transaction on the blockchain which invokes the public function. Contracts can also call public functions from other smart contracts.
Clarity is a list processing (LISP) language, as such it is not compiled. Omitting compilation prevents the possibility of error or bugs introduced at the compiler level. You can write Clarity smart contract programs on any operating system with a text editor. You can use any editor you are comfortable with such as Atom, Vim, or even Notepad. The Clarity files you create with an editor have a `.clar` extension.
Clarity is in pre-release and does not yet directly interact with the live Stacks blockchain. For the pre-release period you need a test environment to run Clarity contracts. Blockstack provides a Docker image called `clarity-developer-preview` that you can use or you can build a test environment locally from code. Either the Docker image or a local environment is sufficient for testing Clarity programming for standalone contracts.
You use the `clarity-cli` command line to check, launch, and execute standalone Clarity contracts inside the virtual test environment. You can use this same command line to create simulate mining Stacks and inspecting a blockchain.
Blockstack expects that some decentralized applications (DApp) will want to make use of Clarity contracts as part of their applications. For this purpose, you should use the Clarity SDK, also in pre-release. The SDK is a development environment, testing framework, and deployment tool. It provides a library for safe interactions with Clarity contracts from a DApp written with the blockstack.js library. The SDK has a `clarity` command line for creating Clarity projects.
## Basic building blocks of Clarity contracts
The basic building blocks of Clarity are _atoms_ and _lists_. An atom is a number or string of contiguous characters. Some examples of atoms:
* `token-sender`
* `10000`
* `SZ2J6ZY48GV1EZ5V2V5RB9MP66SW86PYKKQ9H6DPR`
Atoms can be native functions, user-defined functions, variables, and values that appear in a program. Functions that mutate data by convention terminate with an `!` exclamation point, for example the `insert-entry!` function.
A list is a sequences of atoms enclosed with `()` parentheses. Lists can contain other lists. Some examples of lists are:
* `(get-block-info time 10)`
* `(and 'true 'false)`
* `(is-none? (get id (fetch-entry names-map (tuple (name \"blockstack\")))))`
You can add comments to your Clarity contracts using `;;` (double semi-colons). Both standalone and inline comments are supported.
```cl
;; Transfers tokens to a specified principal
(define-public (transfer (recipient principal) (amount int))
(transfer! tx-sender recipient amount)) ;; returns: boolean
```
You use the `clarity-cli` command to check and launch a Clarity (`.clar`) program.
## hello-world example
The easiest program to run in any language is a hello world program. In Clarity, you can write this `hello-world.clar` program.
```cl
(begin
(print "hello world"))
```
This program defines a single `hello-world` expression that is excuted when the contract launches. The `begin` is a native Clarity function that evaluates the expressions input to it and returns the value of the last expression. Here there is a single `print` expression. Both the `begin` and the `print` are enclosed in `()` parentheses.
For the pre-release, the Blockstack test environment includes the `clarity-cli` command for interacting with the contract and SQLite to support the data space. You create a SQLLite database to hold data related to Clarity contracts. This database simulates the blockchain by recording the contract activity.
You can't run even an a hello-world program without first initializing a Clarity contract's data space within the database. You can use the `clarity-cli initialize` command to set up the database.
```clarity-cli initialize /data/db```
This command initializes the `db` database which resides in the `/data` directory of the container. You can name the database anything you like, the name `db` is not required. You can use SQLite to query this database:
```sql
sqlite> .open db
sqlite> .tables
contracts maps_table type_analysis_table
data_table simmed_block_table
sqlite>
```
After you initialize the contract's data space, you can `check` a Clarity program for problems.
```clarity-cli check ./hello.clar /data/db```
As the name implies, the `check` ensures the contract definition passes a type check; passing programs will returns an exit code of `0` (zero). Once a contract passes a check, you `launch` it.
```bash
root@4224dd95b5f5:/data# clarity-cli launch hello ./hello.clar /data/db
Buffer(BuffData { data: [104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100] })
Contract initialized!
```
Because Clarity does not support simple strings, it stores the `hello world` string in a buffer. Printing out that string displays the ASCII representation for each character. You can see the record of this contract's launch in the corresponding database:
```sql
sqlite> select * from contracts;
1|hello|{"contract_context":{"name":"hello","variables":{},"functions":{}}}
sqlite> select * from type_analysis_table;
1|hello|{"private_function_types":{},"variable_types":{},"public_function_types":{},"read_only_function_types":{},"map_types":{}}
sqlite>
```
## Language rules and limitations
The Clarity smart contract has the following limitations:
Note some of the key Clarity language rules and limitations.
* The only atomic types are booleans, integers, fixed length buffers, and principals
* Recursion is illegal and there is no lambda function.
@ -133,3 +47,6 @@ The Clarity smart contract has the following limitations:
* There is support for lists of the atomic types, however, the only variable length lists in the language appear as function inputs; There is no support for list operations like append or join.
* Variables are created via `let` binding and there is no support for mutating functions like `set`.
## Learning Clarity
You can try a [Hello World tutorial](tutorial.html) or jump right into the [language reference](clarityRef.html).

2
_core/smart/principals.md

@ -3,7 +3,7 @@ layout: core
description: "Blockstack smart contracting language"
permalink: /:collection/:path.html
---
# Principals
# Understanding Principals
{:.no_toc}
_Principals_ are a Clarity native type that represents a spending entity. This section discusses principals and how they are used in the Clarity.

10
_core/smart/sdk-quickstart.md

@ -11,12 +11,6 @@ You can use the software developer kit (SDK) to develop, test, and deploy Clarit
* TOC
{:toc}
<div class="uk-card uk-card-default uk-card-body">
<h5>Clarity is in pre-release</h5>
<p>Clarity, its accompanying toolset, and the SDK are in pre-release. If you encounter issues with or have feature requests regarding Clarity, please create an issue on the <a href='https://github.com/blockstack/blockstack-core/issues' target='_blank'>blockstack/blockstack-core</a> repository. To read previous or join ongoing discussions about smart contracts in general and Clarity in particular, visit the <strong><a href='https://forum.blockstack.org/c/clarity' target='_blank'>Smart Contracts</a></strong> topic in the Blockstack Forum.
</p>
</div>
## About this tutorial and the prerequisites you need
{% include note.html content="This tutorial was written on macOS High Sierra 10.13.4. If you use a Windows or Linux system, you can still follow along. However, you will need to \"translate\" appropriately for your operating system." %}
@ -97,8 +91,8 @@ In this task, you generate a project scaffold &mdash; an initial set of director
Your project should contain three directories:
| Directory |Description |
|---|---|
| Directory | Description |
| -------------- | --------------------------------------------------------- |
| `contracts` | Contains `.clar` files (Clarity contract files) here. |
| `test` | Contains files for testing your application. |
| `node_modules` | Contains packages the project depends on. Added by `npm`. |

169
_core/smart/tutorial-counter.md

@ -0,0 +1,169 @@
---
layout: core
description: "Blockstack Clarity: Counter Tutorial"
permalink: /:collection/:path.html
---
# Tutorial: Counter
| Experience | | **Intermediate** |
| Duration | | **30 minutes** |
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 ...
* Have experienced test-driven development with Clarity
* Understand more Clarity language design principles
* Have a working Clarity counter smart contract
## Overview
* TOC
{:toc}
## Pre-requisites
Before you get started, you should complete the [Hello World tutorial](tutorial.html).
## 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:
```bash
npm init clarity-starter
```
You have to select a template and a name for your local folder. For the counter template used in this tutorial, ensure to type `counter` and hit ENTER:
```bash
? Template - one of [hello-world, counter]: counter
? Project name: (clarity-counter)
```
Finally, the project dependencies are installed and your project is ready for development. Because you already completed the [Hello World tutorial](tutorial.html), the project structure is familiar to you. The main difference is that we have additional tests for a new counter smart contract.
## Step 2: Running tests
mart 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:
Still in the project root directory, run the following command:
```bash
npm test
```
You should see the following response:
```bash
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)
3 failing
```
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.
## Step 3: Developing a smart contract
Let's get familiar with the tests to understand what the new smart contract should look like
1. Take a quick look at the test file associated with the counter smart contract:
```shell
cat test/counter.ts
```
You should be familiar with the test set up from the Hello World tutorial. Notice how the instance of the smart contract is created on line 8:
```js
counterClient = new Client("SP3GWX3NE58KXHESRYE4DYQ1S31PQJTCRXB3PE9SB.counter", "counter", provider);
```
That tells us that the new smart contract is named `counter` and that it should be found in the following file: `contracts/counter.clar`. Note that the `contracts` folder is assumed as the base folder and that every Clarity file has the suffix `.clar`.
The file was already created during the project setup.
2. With the editor of your choice, open the file and add the following lines of code:
```cl
(define-data-var counter int 0)
(define-public (get-counter)
(ok (var-get counter)))
```
The first line initializes a new integer variable `counter` with the value set to `0` using the [`define-data-var`](https://docs.blockstack.org/core/smart/clarityref#define-data-var) statement. It is important to note that all definition statements in Clarity need to be at the top of the file.
To provide access to the `counter` variable from outside of the current smart contract, we need to declare a public function to get it. The last lines of the code add a public `get-counter` function. The [`var-get`](https://docs.blockstack.org/core/smart/clarityref#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!
1. Run the tests and review the results:
```shell
npm test
```
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!
However, we don't stop here. Let's implement increment and decrement functions.
2. Add the following lines to the bottom of the `counter.clar` file and take a few seconds to review them:
```cl
(define-public (increment)
(begin
(var-set counter (+ (var-get counter) 1))
(ok (var-get counter))))
```
First, the [`begin`](https://docs.blockstack.org/core/smart/clarityref#begin) statement evaluates the multi-line expressions and returns the value of the last expression. In this case, it is used to set a new value and return the new value.
Next, a [`var-set`](https://docs.blockstack.org/core/smart/clarityref#var-set) is used to set a new value for the `counter` variable. The new value is constructed using the [`+`](https://docs.blockstack.org/core/smart/clarityref#-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](https://docs.blockstack.org/core/smart/clarityref).
3. Finally, take a few minutes and implement a new public function `decrement` to subtract `1` from the `counter` variable. You should have all knowledge needed to succeed at this!
Done? Great! Run the tests and make sure all of them are passing. You are looking for 4 passed tests:
```shell
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)
```
**Congratulations! You just implemented your first Clarity smart contract.**
4. Here is how the final smart contract file should look like. Note that you can find the `decrement` function in here - in case you want to compare with your own implementation:
```cl
(define-data-var counter int 0)
(define-public (increment)
(begin
(var-set counter (+ (var-get counter) 1))
(ok (var-get counter))))
(define-public (decrement)
(begin
(var-set counter (- (var-get counter) 1))
(ok (var-get counter))))
(define-public (get-counter)
(ok (var-get counter)))
```
## Where to go next
{:.no_toc}
* <a href="principals.html">Guide: Understanding principals</a>
* <a href="clarityRef.html">Clarity language reference</a>

328
_core/smart/tutorial.md

@ -1,308 +1,206 @@
---
layout: core
description: "Blockstack smart contracting language"
description: "Blockstack Clarity: Hello World Tutorial"
permalink: /:collection/:path.html
---
# Hello Clarity for the VM
# Tutorial: Hello World
In this tutorial, you learn how to use Clarity, Blockstack's smart contracting language inside of a virtual environment. The environment is run using a Docker image. Use this tutorial to get a quick introduction to Clarity and the default Blockstack test environment.
| Experience | | **Beginner** |
| Duration | | **15 minutes** |
* TOC
{:toc}
In this tutorial, you learn how to use Clarity, Blockstack's smart contracting language. By the end of this tutorial, you will ...
<div class="uk-card uk-card-default uk-card-body">
<h5>Clarity is in pre-release</h5>
<p>Clarity and its accompanying toolset are in pre-release. If you encounter issues with or have feature requests regarding Clarity, please create an issue on the <a href='https://github.com/blockstack/blockstack-core/issues' target='_blank'>blockstack/blockstack-core</a> repository. To read previous or join ongoing discussions about smart contracts in general and Clarity in particular, visit the <strong><a href='https://forum.blockstack.org/c/clarity' target='_blank'>Smart Contracts</a></strong> topic in the Blockstack Forum.
</p>
</div>
* Have a working Clarity starter project
* Understand basic Clarity language design principles
* Understand how to interact with smart contracts
* Understand how to test smart contracts
## Before you begin (pre-requisites)
## Overview
The Clarity language goes live in the next Stacks blockchain fork. Until the fork, you can run Clarity in a test environment. You run this test environment in a Docker container. Before you begin this tutorial, make sure you have <a href="https://docs.docker.com" target="_blank">Docker installed on your workstation</a>.
* TOC
{:toc}
If, for some reason, you don't want to run the test environment with Docker, you can build and maintain a local environment. Instructions for downloading and building the environment are available in the `blockstack/blockstack-core` repository's <a href='https://github.com/blockstack/blockstack-core' target='_blank'>README</a> file.
## Pre-requisites
To complete the tutorial, you should have [NodeJS](https://nodejs.org/en/download/) installed on your workstation. You can verify your installation by opening up your terminal and run the following command:
## Task 1: Set up the test environment
```shell
npm --version
```
Blockstack publishes the `clarity-developer-preview` image on Docker hub. A container built from this image contains sample programs, the Blockstack Core, and tools for working with them. In this task, you use Docker to pull and run the image on your local workstation.
A version should be returned, indicating that NodeJS installed successfully.
1. Pull the Blockstack core `clarity-developer-preview` image from Docker Hub.
## Step 1: Downloading starter project
```bash
$ docker pull blockstack/blockstack-core:clarity-developer-preview
```
In this step, you initialize a starter project for Clarity development:
2. Start the Blockstack Core test environment with a Bash shell.
1. Using your terminal, run the following command:
```bash
$ docker run -it -v $HOME/blockstack-dev-data:/data/ blockstack/blockstack-core:clarity-developer-preview bash
npm init clarity-starter
```
The command launches a container with the Clarity test environment and opens a bash shell into the container. The `-v` flag creates a local `$HOME/blockstack-dev-data` directory in your workstation and mounts it at the `/data` directory inside the container. The shell opens into the `src/blockstack-core` directory. This directory contains the source for a core and includes Clarity contract samples you can run.
3. List the contents of the `sample-programs` directory.
2. After the starter project was loaded up, have to select a template and a name for your local folder. Feel free to hit ENTER both times to accept the default suggestion.
```bash
root@f88368ba07b2:/src/blockstack-core# ls sample-programs/
names.clar tokens.clar
? Template - one of [hello-world, counter]: (hello-world)
? Project name: (clarity-hello-world)
```
The sample program's directory contains two simple Clarity programs. Clarity code files have a `.clar` suffix.
Finally, the project dependencies are installed and your project is ready for development.
4. Go ahead and display the contents of the `tokens.clar` program with the `cat` command.
3. The project is located in a new folder, `clarity-hello-world` by default. Jump into the folder and have a look at the file structure:
```bash
root@c28600552694:/src/blockstack-core# cat sample-programs/tokens.clar
cd clarity-hello-world
ls
```
The next section gives you an introduction to the Clarity language by way of examining this program's code.
## Task 2: Review a simple Clarity program
If you haven't already done so, use the `cat` or `more` command to display the `tokens.clar` file's code. Clarity is designed for static analysis; it is not a compiled language and is not Turing complete. It language is a LISP-like language. LISP is an acronym for list processing.
The first lines of the `tokens.clar` program contains a user-defined `get-balance` function.
```cl
(define-map tokens ((account principal)) ((balance uint)))
(define-private (get-balance (account principal))
(default-to u0 (get balance (map-get? tokens (tuple (account account))))))
```
`get-balance` is a private function because it is constructed with the `define-private` call. To create public functions, you would use the `define-public` function. Public functions can be called from other contracts or even from the command line with the `clarity-cli`.
Notice the program is enclosed in `()` (parentheses) and each statement as well. The `get-balance` function takes an `account` argument of the special type `principal`. Principals represent a spending entity and are roughly equivalent to a Stacks address.
Along with the `principal` types, Clarity supports booleans, integers, and fixed-length buffers. Variables are created via `let` binding, but there is no support for mutating functions like `set`.
The next sequence of lines shows an `if` statement that allows you to set conditions for execution in the language.
```cl
(define-private (token-credit! (account principal) (amount uint))
(if (<= amount u0)
(err "must move positive balance")
(let ((current-amount (get-balance account)))
(begin
(map-set tokens (tuple (account account))
(tuple (balance (+ amount current-amount))))
(ok amount)))))
```
Every smart contract has both a data space and code. The data space of a contract may only interact with that contract. This particular function is interacting with a map named `tokens`. The `set-entry!` function is a native function that sets the value associated with the input key to the inputted value in the `tokens` data map. Because `set-entry!` mutates data so it has an `!` exclamation point; this is by convention in Clarity.
Take note of the `contracts` and `test` folders. The other files are boilerplate to wire up the project.
In the first `token-transfer` public function, you see that it calls the private `get-balance` function and passes it `tx-sender`. The `tx-sender` is a globally defined variable that represents the current principal.
## Step 2: Reviewing hello world contract
```cl
(define-public (token-transfer (to principal) (amount uint))
(let ((balance (get-balance tx-sender)))
(if (or (> amount balance) (<= amount u0))
(err "must transfer positive balance and possess funds")
(begin
(map-set tokens (tuple (account tx-sender))
(tuple (balance (- balance amount))))
(token-credit! to amount)))))
Now, let's have a look at a Clarity smart contract and get familiar with the basic language design characteristics.
(define-public (mint! (amount uint))
(let ((balance (get-balance tx-sender)))
(token-credit! tx-sender amount)))
(token-credit! 'SZ2J6ZY48GV1EZ5V2V5RB9MP66SW86PYKKQ9H6DPR u10000)
(token-credit! 'SM2J6ZY48GV1EZ5V2V5RB9MP66SW86PYKKQVX8X0G u300)
```
The final two lines of the program pass a principal, represented by a Stacks address, and an amount to the private user-defined `token-credit` function.
Smart contracts may call other smart contracts using a `contract-call!` function. This ability means that if a transaction invokes a function in a given smart contract, that function is able to make calls into other smart contracts on your behalf. The ability to read and do a static analysis of Clarity code allows clients to learn which functions a given smart contract will ever call. Good clients should always warn users about any potential side effects of a given transaction.
Take a moment to `cat` the contents of the `sample-programs/names.clar` file.
```bash
cat sample-programs/names.clar
````
Which `tokens.clar` function is being called?
## Task 3: Initialize data-space and launch contracts
In this task, you interact with the the contracts using the `clarity-cli` command line.
1. Initialize a new `db` database in the `/data/` directory
1. Still inside the terminal, list the contents of the `contracts` folder.
```bash
# clarity-cli initialize /data/db
Database created
ls contracts
```
You should see a message saying `Database created`. The command creates an SQLlite database. The database is available in the container and also in your workstation. In this tutorial, your workstation mount should, at this point, contain the `$HOME/blockstack-dev-data/db` directory.
This directory contains one file for the hello world smart contract. Note that all Clarity files have a `.clar` suffix.
2. Type check the `names.clar` contract.
2. Let's review the contents of `hello-world.clar` with the `cat` command.
```bash
# clarity-cli check sample-programs/names.clar /data/db
cat contracts/hello-world.clar
```
You should get an error:
You should see the contract source code. Take a few seconds to review the content.
```
Error (line 11, column 1): use of unresolved contract ''S1G2081040G2081040G2081040G208105NK8PE5.tokens'.
```
Clarity is a programming language based on [LISP](https://en.wikipedia.org/wiki/Lisp_(programming_language)). Most notably, Clarity is interpreted and decidable.
This happens because the `names.clar` contract _calls_ the `tokens.clar` contract, and that contract has not been created on the blockchain.
Let's go through the source code. Notice how the program and each statement is enclosed in `()` (parentheses). You'll see that the smart contract consists of two public functions. Starting at the top, let's review line by line:
3. Type check the `tokens.clar` contract, it should pass a check as it does not use the `contract-call` function:
```cl
(define-public (say-hi)
(ok "hello world"))
```bash
# clarity-cli check sample-programs/tokens.clar /data/db
Checks passed.
(define-public (echo-number (val int))
(ok val))
```
When the `check` command executes successfully and exits with the stand UNIX `0` exit code.
4. Generate a demo Stacks address for testing your contract.
On the first line, a new public function `say-hi` is declared. To create private functions, you would use the `define-private` keyword. Private functions can only be executed by the current smart contract and not from the outside. Only public functions can be called from outside, by other smart contracts. The reason public functions exist is to enable re-using code that is already available in other smart contracts, and to enable developers to break complex smart contracts into smaller, simpler smart contracts (an exercise in [separating concerns](https://en.wikipedia.org/wiki/Separation_of_concerns)).
This address is used to name your contract at launch time. You can use any existing Stacks address. For this sample, you are going to use the `generate_address` command to create one.
The function doesn't take any parameters and simply returns "hello world" using the [`ok`](https://docs.blockstack.org/core/smart/clarityref#ok) response constructor.
```bash
# clarity-cli generate_address
SP28Z69HE5H70BVRG4VGKN4SYNVJ1J0417WVCKZWM
```
The demo address you generate will be different than the one that appears in this example.
Let's review the second public function, `echo-number`. As opposed to the function before, this takes an input parameter of the type [`int`](https://docs.blockstack.org/core/smart/clarityref#int-type). Along with integer, Clarity supports the following types:
* [uint](https://docs.blockstack.org/core/smart/clarityref#uint-type): 16-byte unsigned integer
* [principal](https://docs.blockstack.org/core/smart/clarityref#principal-type): spending entity, roughly equivalent to a Stacks address
* [boolean](https://docs.blockstack.org/core/smart/clarityref#bool-type): `true` or `false`
* [buffer](https://docs.blockstack.org/core/smart/clarityref#buffer-type): fixed-length byte buffers
* [tuple](https://docs.blockstack.org/core/smart/clarityref#tuple-type): named fields in keys and values
5. Add the address to your environment.
The function simply uses the `ok` response and returns the value passed to the function.
```bash
# DEMO_ADDRESS=SP28Z69HE5H70BVRG4VGKN4SYNVJ1J0417WVCKZWM
```
## Step 3: Running tests
6. Launch the `tokens.clar` contract and assign it to your `DEMO_ADDRESS` address.
The starter project comes with test tooling already set up for you (using [Mocha](https://mochajs.org/)). Let's run the tests and review the results:
You use the `launch` command to instantiate a contract on the Stacks blockchain. If you have dependencies between contracts, for example `names.clar` is dependent on `tokens.clar`, you must launch the dependency first.
```bash
# clarity-cli launch $DEMO_ADDRESS.tokens sample-programs/tokens.clar /data/db
Contract initialized!
```
Once launched, you can execute the contract or a public method on the contract. Your development database has an instantiated `tokens` contract. If you were to close the container and restart it later with the same mount point and you wouldn't need to relaunch that database; it persists until you remove it from your local drive.
7. Instantiate the `names.clar` contract and assign it to your `DEMO_ADDRESS` address. as well.
```bash
# clarity-cli launch $DEMO_ADDRESS.names sample-programs/names.clar /data/db
Contract initialized!
```
## Task 4. Examine the SQLite database
The test environment uses a SQLite database to represent a virtual blockchain. You initialized this database when you ran this earlier:
Still in the project root directory, run the following command:
```bash
clarity-cli initialize /data/db
npm test
```
As you work the contracts, data is added to the `db` database because you pass this database as a parameter, for example:
You should see the following response:
```bash
clarity-cli launch $DEMO_ADDRESS.tokens sample-programs/tokens.clar /data/db
```
hello world contract test suite
✓ should have a valid syntax
deploying an instance of the contract
✓ should return 'hello world'
✓ should echo number
The database exists on your local workstation and persists through restarts of the container. You can use this database to explore the transactional effects of your Clarity programs. The SQLite database includes a single `data_table` and a set of `marf` structures.
While not required, you can install SQLite in your local environment and use it to examine the data associated with and impacted by your contract. For example, this what the `data_able` contains after you initialize the `tokens` contract.
3 passing (412ms)
```
<img src="../images/sqlite-contract.png" alt="">
Great, all tests are passing! Now, let's have a look at the test implementation. That helps understand how to interact with Clarity smart contracts.
The `marf` directory defines a data structure that handles key-value lookups in the presence of blockchain forks. These structures are not intended for use in debugging, they simply support the implementation.
## Step 4: Interacting with contracts
Tests are located in the `test` folder, let's have a look at the tests associated with the `hello-world.clar` file.
## Task 5: Execute a public function
Run the following command:
In this section, you use the public `mint!` function in the `tokens` contract to mint some new tokens.
```bash
cat test/hello-world.ts
```
1. Get the current balance of your new address.
Take a few seconds to review the contents of the file. You should ignore the test setup functions and focus on the most relevant parts related to Clarity.
```bash
# echo "(get-balance '$DEMO_ADDRESS)" | clarity-cli eval $DEMO_ADDRESS.tokens /data/db
Program executed successfully! Output:
0
```
Note that we're importing modules from the `@blockstack/clarity` package:
This command uses the private `get-balance` function in the `tokens` contract and pipes the result to the `eval` subcommand. The `eval` subcommand lets you evaluate both public and _private_ functions of a contract in read-only mode.
```js
import { Client, Provider, ProviderRegistry, Result } from "@blockstack/clarity";
```
2. Try minting some tokens and sending them to an address we'll use for our demo.
### Initiliazing a client
```bash
# clarity-cli execute /data/db $DEMO_ADDRESS.tokens mint! $DEMO_ADDRESS u100000
Transaction executed and committed. Returned: 100000
```
At the test start, we are initializing contract instance `helloWorldClient` and a provider that simulates interactions with the Stacks 2.0 blockchain.
This executes the public `mint!` function defined in the tokens contract, sending 100000 tokens to you `$DEMO_ADDRESS`.
```js
let helloWorldClient: Client;
let provider: Provider;
3. Use the `clarity-cli eval` command to check the result of this call.
(...)
```bash
# echo "(get-balance '$DEMO_ADDRESS)" | clarity-cli eval $DEMO_ADDRESS.tokens /data/db
Program executed successfully! Output:
100000
```
## Task 6: Spend tokens by registering a name
provider = await ProviderRegistry.createProvider();
helloWorldClient = new Client("SP3GWX3NE58KXHESRYE4DYQ1S31PQJTCRXB3PE9SB.hello-world", "hello-world", provider);
```
Now, let's register a name using the `names.clar` contract. Names can _only_ be integers in this sample contract, so you'll register the name 10 in this environment.
Take a look at the client initialization. It requires a contract id and name in the following format: `{owner_stacks_address}.{contract_identifier}`. The second field indicates the location of the smart contract file, without the `.clar` suffix. By default, the location is assumed to be relative to the `contracts` folder.
1. Compute the hash of the name we want to register.
As you can see above, a sample Stacks address and contract identifier is already provided for you. You don't need to modify anything.
You'll _salt_ the hash with the salt `8888`:
### Checking syntax
```bash
# echo "(hash160 (xor 10 8888))" | clarity-cli eval $DEMO_ADDRESS.names /data/db
Program executed successfully! Output:
0xb572fb1ce2e9665f1efd0994fe077b50c3a48fde
```
Next, we check the contract for valid syntax. If the smart contract implementation has syntax error (bugs), this check would fail:
The value of the name hash is:
```js
await helloWorldClient.checkContract();
```
```
0xb572fb1ce2e9665f1efd0994fe077b50c3a48fde
```
Note that the `checkContract()` function returns a [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise). The `await` command makes sure JavaScript is not executing the next lines until the contract check completes.
2. Preorder the name using the _execute_ command:
### Deploying contract
```bash
# clarity-cli execute /data/db $DEMO_ADDRESS.names preorder $DEMO_ADDRESS 0xb572fb1ce2e9665f1efd0994fe077b50c3a48fde u1000
e077b50c3a48fde 1000
Transaction executed and committed. Returned: 0
```
Further down in the file, you find a contract deployment:
This executes the public `preorder` function defined in the `names.clar` contract. The function reserves a name by paying the name fee (in this case, 1000 tokens).
```js
await helloWorldClient.deployContract();
```
3. Check the demo address' new balance:
### Run public functions
```bash
# echo "(get-balance '$DEMO_ADDRESS)" | clarity-cli eval $DEMO_ADDRESS.tokens /data/db
Program executed successfully! Output:
99000
```
Finally, you will find snippets that call the public `say-hi` function of the contract:
4. Register the name by executing the _register_ function:
```js
const query = helloWorldClient.createQuery({ function: { name: "say-hi", args: [] } });
const receipt = await helloWorldClient.submitQuery(query);
const result = Result.unwrapString(receipt);
```
```bash
# clarity-cli execute /data/db $DEMO_ADDRESS.names register $DEMO_ADDRESS \'$DEMO_ADDRESS 10 8888
Transaction executed and committed. Returned: 0
```
As you see, smart contract calls are realized through query definitions. The `createQuery` function defines the name and arguments passed to the smart contract function. With `submitQuery`, the function executed and the response is wrapped into a `Result` object. To obtain the readable result, we use the `unwrapString` function, which should return `hello world`.
5. Lookup the "owner address" for the name:
Now, review the last test `should echo number` on your own and try to understand how arguments are passed to the `echo-number` smart contract.
```bash
# echo "(get owner (map-get name-map (tuple (name 10))))" | clarity-cli eval $DEMO_ADDRESS.names /data/db
Program executed successfully! Output:
(some 'SP2Y8T8RWWXFR8S1XBP6K0MHCQF01D552FSWD9M4E)
```
With that, you have completed the first Clarity tutorial! Congratulations!
## Where to go next
{:.no_toc}
* <a href="clarityRef.html">Clarity Language Reference</a>
* <a href="clarityCLI.html">clarity-cli command line</a>
* <a href="tutorial-counter.html">Next tutorial: Writing a counter smart contract</a>
* <a href="clarityRef.html">Clarity language reference</a>

23
_data/navigation_core.yml

@ -1,4 +1,15 @@
- title: Overview
- title: Smart Contracts
docs:
- core/smart/overview
- core/smart/tutorial
- core/smart/tutorial-counter
- core/smart/principals
- core/smart/functions
- core/smart/clarityRef
- core/smart/clarityCLI
- core/smart/sdk-quickstart
- title: Naming Services
docs:
- core/naming/introduction
- core/naming/architecture
@ -11,16 +22,6 @@
- core/naming/search
- core/faq_technical
- title: Clarity Smart Contracts
docs:
- core/smart/overview
- core/smart/principals
- core/smart/functions
- core/smart/tutorial
- core/smart/clarityRef
- core/smart/clarityCLI
- core/smart/sdk-quickstart
- title: How to use BNS
docs:
- core/naming/pickname

26
_data/navigation_home.yml

@ -1,24 +1,24 @@
# Categories home page navigation
- title: Evaluate the Blockstack Ecosystem
desc: Learn the components that make up the Blockstack Ecosystem. Understand the value a blockchain offers.
icon: info
doc: org/overview
- title: Use Blockchain Applications
desc: Learn about the New Internet and blockchain applications. Create an identity and learn how to use it.
icon: settings
doc: browser/browser-introduction
- title: Build Blockchain Applications
- title: Build Decentralized Apps
desc: Learn how to build a blockchain application with Blockstack. Work through web and mobile tutorials.
icon: code
doc: develop/zero_to_dapp_1
- title: Blockstack Core
- title: Build Smart Contracts
desc: Work with our Core node, smart contracts, namespaces, zone files, and other advanced topics.
icon: cog
doc: core/naming/introduction
doc: core/smart/overview
- title: Use Blockchain Apps
desc: Learn about the New Internet and blockchain applications. Create an identity and learn how to use it.
icon: settings
doc: browser/browser-introduction
- title: Evaluate the Blockstack Ecosystem
desc: Learn the components that make up the Blockstack Ecosystem. Understand the value a blockchain offers.
icon: info
doc: org/overview
- title: Implement Storage with Gaia
desc: Backend storage drivers and interactions between developer APIs and the Gaia service.

7
_sass/syntax-highlighting/github.scss

@ -3,8 +3,13 @@
*/
a>.highlight,
.highlighter-rouge {
color: inherit !important;
}
.highlight, .highlighter-rouge {
.highlight,
.highlighter-rouge {
background-color: #F7F8FA;
color: #5A6575;
border: none;

Loading…
Cancel
Save