Clarity
Clarity- smart contract language reference
Others • blockstack app store posted the article • 0 comments • 1606 views • 2019-06-28 01:45
This file contains the reference for the Clarity language.
Block Properties
Supported types
Int type
Bool type
Buffer type
List type
Principal type
Tuple type
Optional type
Response type
Native variables
block-height
contract-name
tx-sender
Clarity function reference
* (multiply)
+ (add)
- (subtract)
/ (divide)
< (less than)
<= (less than or equal)
> (greater than)
>= (greater than or equal)
and
as-contract
begin
contract-call!
default-to
define-data-var
define-map
define-public
define-read-only
define
delete-entry!
eq?
err
expects!
expects-err!
fetch-contract-entry
fetch-entry
fetch-var
filter
fold
get-block-info
get
hash160
if
insert-entry!
is-none?
is-ok?
keccak256
let
list
map
mod
not
ok
or
pow
set-entry!
set-var!
sha256
tuple
xor
Block Properties
The get-block-info function fetches property details for a block at a specified block height. For example:
(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:
Property
Definition
header-hash
A 32-byte buffer containing the block hash.
burnchain-header-hash
A 32-byte buffer that contains the hash from the proof of burn.
vrf-seed
A 32-byte buffer containing the Verifiable Random Function (VRF) seed value used for the block.
time
An integer value containing that roughly corresponds to when the block was mined. This is a Unix epoch timestamp in seconds.
Warning: The time does not increase monotonically with each block. Block times are accurate only to within two hours. See BIP113 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.
Int type
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.
Bool type
Supports values of 'true or 'false.
Buffer type
Buffer types represent fixed-length byte buffers. Currently, the only way to construct a Buffer is using string literals, for example "alice.id" or hash160("bob.id")
All of the hash functions return buffers:
hash160 sha256 keccak256
The block properties header-hash, burnchain-header-hash, and vrf-seed are all buffers.
List type
Clarity supports 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.
Principal type
Clarity provides this primitive for checking whether or not the smart contract transaction was signed by a particular principal. Principals represent a spending entity and are roughly equivalent to a Stacks address. The principal’s signature is not checked by the smart contract, but by the virtual machine. A smart contract function can use the globally defined tx-sender variable to obtain the current principal.
Smart contracts may also be principals (represented by the smart contract’s identifier). However, there is no private key associated with the smart contract, and it cannot broadcast a signed transaction on the blockchain. A smart contract uses the special variable contract-name to refer to its own principal.
Tuple type
To support the use of named fields in keys and values, Clarity allows the construction of named tuples using a function (tuple ...), for example
(define imaginary-number-a (tuple (real 1) (i 2)))
(define imaginary-number-b (tuple (real 2) (i 3)))
This allows for creating named tuples on the fly, which is useful for data maps where the keys and values are themselves named tuples. Values in a given mapping are set or fetched using:
Function
Description
(fetch-entry map-name key-tuple)
Fetches the value associated with a given key in the map, or returns none if there is no such value.
(set-entry! map-name key-tuple value-tuple)
Sets the value of key-tuple in the data map
(insert-entry! map-name key-tuple value-tuple)
Sets the value of key-tuple in the data map if and only if an entry does not already exist.
(delete-entry! map-name key-tuple)
Deletes key-tuple from the data map.
To access a named value of a given tuple, the (get name tuple) function returns that item from the tuple.
Optional type
Represents an optional value. This is used in place of the typical usage of “null” values in other languages, and represents a type that can either be some value or none. Optional types are used as the return types of data-map functions.
Response type
Response types represent the result of a public function. Use this type to indicate and return data associated with the execution of the function. Also, the response should indicate whether the function error’ed (and therefore did not materialize any data in the database) or ran ok (in which case data materialized in the database).
Response types contain two subtypes – a response type in the event of ok (that is, a public function returns an integer code on success) and an err type (that is, a function returns a buffer on error).
Native variables
The Clarity language includes native variables you can use in your contract.
block-height
The height of a block in the Stacks blockchain. Block height is the number of blocks in the chain between any given block and the very first block in the blockchain. You can obtain a block-height via the get-block-info function.
contract-name
Represents the current contract.
tx-sender
Represents the current principal. This variable does not change during inter-contract calls. This 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. This enables a wide variety of applications, but it comes with some dangers for users of smart contracts. Static analysis of Clarity contracts guarantees the language allows clients to deduce which functions a given smart contract will ever call. Good clients should always warn users about any potential side effects of a given transaction.
Clarity function reference
* (multiply)
Syntax (* i1 i2...)
Input type:
int, ...
Output type:
int
Multiplies a variable number of integer inputs and returns the result. In the event of an overflow, throws a runtime error.
Example
(* 2 3) ;; Returns 6
(* 5 2) ;; Returns 10
(* 2 2 2) ;; Returns 8
+ (add)
Syntax (+ i1 i2...)
Input type:
int, ...
Output type:
int
Adds a variable number of integer inputs and returns the result. In the event of an overflow, throws a runtime error.
Example
(+ 1 2 3) ;; Returns 6
- (subtract)
Syntax (- i1 i2...)
Input type:
int, ...
Output type:
int
Subtracts a variable number of integer inputs and returns the result. In the event of an underflow, throws a runtime error.
Example
(- 2 1 1) ;; Returns 0
(- 0 3) ;; Returns -3
/ (divide)
Syntax (/ i1 i2...)
Input type:
int, ...
Output type:
int
Integer divides a variable number of integer inputs and returns the result. In the event of division by zero, throws a runtime error.
Example
(/ 2 3) ;; Returns 0
(/ 5 2) ;; Returns 2
(/ 4 2 2) ;; Returns 1
< (less than)
Syntax (< i1 i2)
Input type:
int, int
Output type:
bool
Compares two integers, returning true if i1 is less than i2 and false otherwise.
Example
(< 1 2) ;; Returns 'true
(< 5 2) ;; Returns 'false
<= (less than or equal)
Syntax (> i1 i2)
Input type:
int, int
Output type:
bool
Compares two integers, returning true if i1 is less than or equal to i2 and false otherwise.
Example
(<= 1 1) ;; Returns 'true
(<= 5 2) ;; Returns 'false
> (greater than)
Syntax (> i1 i2)
Input type:
int, int
Output type:
bool
Compares two integers, returning true if i1 is greater than i2 and false otherwise.
Example
(> 1 2) ;; Returns 'false
(> 5 2) ;; Returns 'true
>= (greater than or equal)
Syntax (>= i1 i2)
Input type:
int, int
Output type:
bool
Compares two integers, returning true if i1 is greater than or equal to i2 and false otherwise.
Example
(>= 1 1) ;; Returns 'true
(>= 5 2) ;; Returns 'true
and
Syntax (and b1 b2 ...)
Input type:
bool, ...
Output type:
bool
Returns true if all boolean inputs are true. Importantly, the supplied arguments are evaluated in-order and lazily. Lazy evaluation means that if one of the arguments returns false, the function short-circuits, and no subsequent arguments are evaluated.
Example
(and 'true 'false) ;; Returns 'false
(and (eq? (+ 1 2) 1) (eq? 4 4)) ;; Returns 'false
(and (eq? (+ 1 2) 3) (eq? 4 4)) ;; Returns 'true
as-contract
Syntax (as-contract expr)
Input type:
A
Output type:
A
The as-contract function switches the current context’s tx-sender value to the contract’s principal and executes expr with that context. It returns the resulting value of expr.
Example
(as-contract (print tx-sender)) ;; Returns 'CTcontract.name
begin
Syntax (begin expr1 expr2 expr3 ... expr-last)
Input type:
AnyType, ... A
Output type:
A
The begin function evaluates each of its input expressions, returning the return value of the last such expression.
Example
(begin (+ 1 2) 4 5) ;; Returns 5
contract-call!
Syntax (contract-call! contract-name function-name arg0 arg1 ...)
Input type:
ContractName, PublicFunctionName, Arg0, ...
Output type:
Response(A,B)
The contract-call! function executes the given public function of the given contract. You may not this function to call a public function defined in the current contract. If the public function returns err, any database changes resulting from calling contract-call! are aborted. If the function returns ok, database changes occurred.
Example
(contract-call! tokens transfer 'SZ2J6ZY48GV1EZ5V2V5RB9MP66SW86PYKKQ9H6DPR 19) ;; Returns (ok 1)
default-to
Syntax (default-to default-value option-value)
Input type:
A, Optional(A)
Output type:
A
The default-to function attempts to ‘unpack’ the second argument: if the argument is a (some ...) option, it returns the inner value of the option. If the second argument is a (none) value, default-to it returns the value of default-value.
Example
(default-to 0 (get id (fetch-entry names-map (tuple (name "blockstack"))))) ;; Returns 1337
(default-to 0 (get id (fetch-entry names-map (tuple (name "non-existant"))))) ;; Returns 0
define-data-var
Syntax (define-data-var var-name type value)
Input type:
VarName, TypeDefinition, Value
Output type:
Not Applicable
define-data-var is used to define a new persisted variable for use in a smart contract. Such variable are only modifiable by the current smart contract.
Persisted variable are defined with a type and a value.
Like other kinds of definition statements, define-data-var may only be used at the top level of a smart contract definition (i.e., you cannot put a define statement in the middle of a function body).
Example
(define-data-var size int 0)
(define (set-size (value int))
(set-var! size value))
(set-size 1)
(set-size 2)
define-map
Syntax (define-map map-name ((key-name-0 key-type-0) ...) ((val-name-0 val-type-0) ...))
Input type:
MapName, KeyTupleDefinition, MapTupleDefinition
Output type:
Not Applicable
define-map is used to define a new datamap for use in a smart contract. Such maps are only modifiable by the current smart contract.
Maps are defined with a key tuple type and value tuple type. These are defined using a list of name and type pairs, e.g., a key type might be ((id int)), which is a tuple with a single “id” field of type int.
Like other kinds of definition statements, define-map may only be used at the top level of a smart contract definition (i.e., you cannot put a define statement in the middle of a function body).
Example
(define-map squares ((x int)) ((square int)))
(define (add-entry (x int))
(insert-entry! squares ((x 2)) ((square (* x x)))))
(add-entry 1)
(add-entry 2)
(add-entry 3)
(add-entry 4)
(add-entry 5)
define-public
Syntax (define-public (function-name (arg-name-0 arg-type-0) (arg-name-1 arg-type-1) ...) function-body)
Input type:
MethodSignature, MethodBody
Output type:
Not Applicable
define-public is used to define a public function and transaction for a smart contract. Public functions are callable from other smart contracts and may be invoked directly by users by submitting a transaction to the Stacks blockchain.
Like other kinds of definition statements, define-public may only be used at the top level of a smart contract definition (i.e., you cannot put a define statement in the middle of a function body).
Public functions must return a ResponseType (using either ok or err). Any datamap modifications performed by a public function is aborted if the function returns an err type. Public functions may be invoked by other contracts via contract-call!.
Example
(define-public (hello-world (input int))
(begin (print (+ 2 input))
(ok input)))
define-read-only
Syntax (define-read-only (function-name (arg-name-0 arg-type-0) (arg-name-1 arg-type-1) ...) function-body)
Input type:
MethodSignature, MethodBody
Output type:
Not Applicable
define-read-only is used to define a public read-only function for a smart contract. Such functions are callable from other smart contracts.
Like other kinds of definition statements, define-read-only may only be used at the top level of a smart contract definition (i.e., you cannot put a define statement in the middle of a function body).
Read-only functions may return any type. However, read-only functions may not perform any datamap modifications, or call any functions which perform such modifications. This is enforced both during type checks and during the execution of the function. Public read-only functions may be invoked by other contracts via contract-call!.
Example
(define-read-only (just-return-one-hundred)
(* 10 10))
define
Syntax (define (function-name (arg-name-0 arg-type-0) (arg-name-1 arg-type-1) ...) function-body)
Input type:
MethodSignature, MethodBody
Output type:
Not Applicable
define is used to define private functions for a smart contract. Private functions may not be called from other smart contracts, nor may they be invoked directly by users. Instead, these functions may only be invoked by other functions defined in the same smart contract.
Like other kinds of definition statements, define may only be used at the top level of a smart contract definition (i.e., you cannot put a define statement in the middle of a function body).
Private functions may return any type.
Example
(define (max-of (i1 int) (i2 int))
(if (> i1 i2)
i1
i2))
(max-of 4 6) ;; returns 6
delete-entry!
Syntax (delete-entry! map-name key-tuple)
Input type:
MapName, Tuple
Output type:
bool
The delete-entry! function removes the value associated with the input key for the given map. If an item exists and is removed, the function returns true. If a value did not exist for this key in the data map, the function returns false.
Example
(delete-entry! names-map (tuple (name "blockstack"))) ;; Returns 'true
(delete-entry! names-map (tuple (name "blockstack"))) ;; Returns 'false
(delete-entry! names-map ((name "blockstack"))) ;; Same command, using a shorthand for constructing the tuple
eq?
Syntax (eq? v1 v2...)
Input type:
A, A, ...
Output type:
bool
Compares the inputted values, returning true if they are all equal. Note that unlike the (and ...) function, (eq? ...) will not short-circuit.
Example
(eq? 1 1) ;; Returns 'true
(eq? 1 'false) ;; Returns 'false
(eq? "abc" 234 234) ;; Returns 'false
err
Syntax (err value)
Input type:
A
Output type:
Response(A,B)
The err function constructs a response type from the input value. Use err for creating return values in public functions. An err value indicates that any database changes during the processing of the function should be rolled back.
Example
(err 'true) ;; Returns (err 'true)
expects!
Syntax (expects! option-input thrown-value)
Input type:
Optional(A) | Response(A,B), C
Output type:
A
The expects! function attempts to ‘unpack’ the first argument: if the argument is an option type, and the argument is a (some ...) option, expects! returns the inner value of the option. If the argument is a response type, and the argument is an (ok ...) response, expects! returns the inner value of the ok. If the supplied argument is either an (err ...) or a (none) value, expects! returns thrown-value from the current function and exits the current control-flow.
Example
(expects! (fetch-entry names-map (tuple (name "blockstack"))) (err 1)) ;; Returns (tuple (id 1337))
expects-err!
Syntax (expects-err! response-input thrown-value)
Input type:
Response(A,B), C
Output type:
B
The expects-err! function attempts to ‘unpack’ the first argument: if the argument is an (err ...) response, expects-err! returns the inner value of the err. If the supplied argument is an (ok ...) value, expects-err! returns thrown-value from the current function and exits the current control-flow.
Example
(expects-err! (err 1) 'false) ;; Returns 1
fetch-contract-entry
Syntax (fetch-contract-entry contract-name map-name key-tuple)
Input type:
ContractName, MapName, Tuple
Output type:
Optional(Tuple)
The fetch-contract-entry function looks up and returns an entry from a contract other than the current contract’s data map. The value is looked up using key-tuple. If there is no value associated with that key in the data map, the function returns a (none) option. Otherwise, it returns (some value).
Example
(expects! (fetch-contract-entry names-contract names-map (tuple (name "blockstack")) (err 1))) ;; Returns (tuple (id 1337))
(expects! (fetch-contract-entry names-contract names-map ((name "blockstack")) (err 1)));; Same command, using a shorthand for constructing the tuple
fetch-entry
Syntax (fetch-entry map-name key-tuple)
Input type:
MapName, Tuple
Output type:
Optional(Tuple)
The fetch-entry function looks up and returns an entry from a contract’s data map. The value is looked up using key-tuple. If there is no value associated with that key in the data map, the function returns a (none) option. Otherwise, it returns (some value)
Example
(expects! (fetch-entry names-map (tuple (name "blockstack"))) (err 1)) ;; Returns (tuple (id 1337))
(expects! (fetch-entry names-map ((name "blockstack"))) (err 1)) ;; Same command, using a shorthand for constructing the tuple
fetch-var
Syntax (fetch-var var-name)
Input type:
VarName
Output type:
A
The fetch-var function looks up and returns an entry from a contract’s data map. The value is looked up using var-name.
Example
(fetch-var cursor) ;; Returns cursor
filter
Syntax (filter func list)
Input type:
Function(A) -> bool, (list A)
Output type:
(list A)
The filter function applies the input function func to each element of the input list, and returns the same list with any elements removed for which the func returned false.
Example
(filter not (list true false true false)) ;; Returns (list false false)
fold
Syntax (fold func list initial-value)
Input type:
Function(A, B) -> B, (list A)
Output type:
B
The fold function applies the input function func to each element of the input list and the output of the previous application of the fold function. When invoked on the first list element, it uses the initial-value as the second input. fold returns the last value return by the successive applications.
Example
(fold * (list 2 2 2) 1) ;; Returns 8
(fold * (list 2 2 2) 0) ;; Returns 0
get-block-info
Syntax (get-block-info prop-name block-height-expr)
Input type:
BlockInfoPropertyName, BlockHeightInt
Output type:
buff | int
The get-block-info function fetches data for a block of the given block height. The value and type returned are determined by the specified BlockInfoPropertyName. If the provided BlockHeightInt does not correspond to an existing block, the function is aborted. The currently available property names are time, header-hash, burnchain-header-hash, and vrf-seed.
The time property returns an integer value of the block header time field. This is a Unix epoch timestamp in seconds which roughly corresponds to when the block was mined. Warning: this does not increase monotonically with each block and block times are accurate only to within two hours. See BIP113 for more information.
The header-hash, burnchain-header-hash, and vrf-seed properties return a 32-byte buffer.
Example
(get-block-info time 10) ;; Returns 1557860301
(get-block-info header-hash 2) ;; Returns 0x374708fff7719dd5979ec875d56cd2286f6d3cf7ec317a3b25632aab28ec37bb
(get-block-info vrf-seed 6) ;; Returns 0xf490de2920c8a35fabeb13208852aa28c76f9be9b03a4dd2b3c075f7a26923b4
get
Syntax (get key-name tuple)
Input type:
KeyName and Tuple | Optional(Tuple)
Output type:
AnyType
The get function fetches the value associated with a given key from the supplied typed tuple. If an Optional value is supplied as the inputted tuple, get returns an Optional type of the specified key in the tuple. If the supplied option is a (none) option, get returns (none).
Example
(get id (tuple (name "blockstack") (id 1337))) ;; Returns 1337
(get id (fetch-entry names-map (tuple (name "blockstack")))) ;; Returns (some 1337)
(get id (fetch-entry names-map (tuple (name "non-existent")))) ;; Returns (none)
hash160
Syntax (hash160 value)
Input type:
buff|int
Output type:
(buff 20)
The hash160 function computes RIPEMD160(SHA256(x)) of the inputted value. If an integer (128 bit) is supplied the hash is computed over the little-endian representation of the integer.
Example
(hash160 0) ;; Returns 0xe4352f72356db555721651aa612e00379167b30f
if
Syntax (if bool1 expr1 expr2)
Input type:
bool, A, A
Output type:
A
The if function admits a boolean argument and two expressions which must return the same type. In the case that the boolean input is true, the if function evaluates and returns expr1. If the boolean input is false, the if function evaluates and returns expr2.
Example
(if true 1 2) ;; Returns 1
(if (> 1 2) 1 2) ;; Returns 2
insert-entry!
Syntax (insert-entry! map-name key-tuple value-tuple)
Input type:
MapName, TupleA, TupleB
Output type:
bool
The insert-entry! function sets the value associated with the input key to the inputted value if and only if there is not already a value associated with the key in the map. If an insert occurs, the function returns true. If a value already existed for this key in the data map, the function returns false.
Example
(insert-entry! names-map (tuple (name "blockstack")) (tuple (id 1337))) ;; Returns 'true
(insert-entry! names-map (tuple (name "blockstack")) (tuple (id 1337))) ;; Returns 'false
(insert-entry! names-map ((name "blockstack")) ((id 1337))) ;; Same command, using a shorthand for constructing the tuple
is-none?
Syntax (is-none? value)
Input type:
Optional(A)
Output type:
bool
is-none? tests a supplied option value, returning true if the option value is (none), and false if it is a (some ...).
Example
(is-none? (get id (fetch-entry names-map (tuple (name "blockstack"))))) ;; Returns 'false
(is-none? (get id (fetch-entry names-map (tuple (name "non-existant"))))) ;; Returns 'true
is-ok?
Syntax (is-ok? value)
Input type:
Response(A,B)
Output type:
bool
is-ok? tests a supplied response value, returning true if the response was ok, and false if it was an err.
Example
(is-ok? (ok 1)) ;; Returns 'true
(is-ok? (err 1)) ;; Returns 'false
keccak256
Syntax (keccak256 value)
Input type:
buff|int
Output type:
(buff 32)
The keccak256 function computes KECCAK256(value) of the inputted value. Note that this differs from the NIST SHA-3 (that is, FIPS 202) standard. If an integer (128 bit) is supplied the hash is computed over the little-endian representation of the integer.
Example
(keccak256 0) ;; Returns 0xf490de2920c8a35fabeb13208852aa28c76f9be9b03a4dd2b3c075f7a26923b4
let
Syntax (let ((name1 expr1) (name2 expr2) ...) expr-body)
Input type:
((name2 AnyType) (name2 AnyType) ...), A
Output type:
A
The let function accepts a list of variable name and expression pairs, evaluating each expression and binding it to the corresponding variable name. The context created by this set of bindings is used for evaluating and return the value of expr-body.
Example
(let ((a 2) (b (+ 5 6 7))) (+ a b)) ;; Returns 20
list
Syntax (list expr1 expr2 expr3 ...)
Input type:
A, ...
Output type:
(list A)
The list function constructs a list composed of the inputted values. Each supplied value must be of the same type.
Example
(list (+ 1 2) 4 5) ;; Returns [3 4 5]
map
Syntax (map func list)
Input type:
Function(A) -> B, (list A)
Output type:
(list B)
The map function applies the input function func to each element of the input list, and outputs a list containing the outputs from those function applications.
Example
(map not (list true false true false)) ;; Returns 'false true false true
mod
Syntax (mod i1 i2)
Input type:
int, int
Output type:
int
Returns the integer remainder from integer dividing i1 by i2. In the event of a division by zero, throws a runtime error.
Example
(mod 2 3) ;; Returns 0
(mod 5 2) ;; Returns 1
(mod 7 1) ;; Returns 0
not
Syntax (not b1)
Input type:
bool
Output type:
bool
Returns the inverse of the boolean input.
Example
(not 'true) ;; Returns 'false
(not (eq? 1 2)) ;; Returns 'true
ok
Syntax (ok value)
Input type:
A
Output type:
Response(A,B)
The ok function constructs a response type from the input value. Use ok for creating return values in public functions. An ok value indicates that any database changes during the processing of the function should materialize.
Example
(ok 1) ;; Returns (ok 1)
or
Syntax (or b1 b2 ...)
Input type:
bool, ...
Output type:
bool
Returns true if any boolean inputs are true. Importantly, the supplied arguments are evaluated in-order and lazily. Lazy evaluation means that if one of the arguments returns false, the function short-circuits, and no subsequent arguments are evaluated.
Example
(or 'true 'false) ;; Returns 'true
(or (eq? (+ 1 2) 1) (eq? 4 4)) ;; Returns 'true
(or (eq? (+ 1 2) 1) (eq? 3 4)) ;; Returns 'false
(or (eq? (+ 1 2) 3) (eq? 4 4)) ;; Returns 'true
pow
Syntax (pow i1 i2)
Input type:
int, int
Output type:
int
Returns the result of raising i1 to the power of i2. In the event of an overflow, throws a runtime error.
Example
(pow 2 3) ;; Returns 8
(pow 2 2) ;; Returns 4
(pow 7 1) ;; Returns 7
Syntax (print expr)
Input type:
A
Output type:
A
The print function evaluates and returns its input expression. On Blockstack Core nodes configured for development (as opposed to production mining nodes), this function prints the resulting value to STDOUT (standard output).
Example
(print (+ 1 2 3)) ;; Returns 6
set-entry!
Syntax (set-entry! map-name key-tuple value-tuple)
Input type:
MapName, TupleA, TupleB
Output type:
bool
The set-entry! function sets the value associated with the input key to the inputted value. This function performs a blind update; whether or not a value is already associated with the key, the function overwrites that existing association.
Example
(set-entry! names-map (tuple (name "blockstack")) (tuple (id 1337))) ;; Returns 'true
(set-entry! names-map ((name "blockstack")) ((id 1337))) ;; Same command, using a shorthand for constructing the tuple
set-var!
Syntax (set-var! var-name expr1)
Input type:
VarName, AnyType
Output type:
bool
The set-var! function sets the value associated with the input variable to the inputted value.
Example
(set-var! cursor (+ cursor 1)) ;; Returns 'true
sha256
Syntax (sha256 value)
Input type:
buff|int
Output type:
(buff 32)
The sha256 function computes SHA256(x) of the inputted value. If an integer (128 bit) is supplied the hash is computed over the little-endian representation of the integer.
Example
(sha256 0) ;; Returns 0x374708fff7719dd5979ec875d56cd2286f6d3cf7ec317a3b25632aab28ec37bb
tuple
Syntax (tuple ((key0 expr0) (key1 expr1) ...))
Input type:
(list (KeyName AnyType))
Output type:
Tuple
The tuple function constructs a typed tuple from the supplied key and expression pairs. A get function can use typed tuples as input to select specific values from a given tuple. Key names may not appear multiple times in the same tuple definition. Supplied expressions are evaluated and associated with the expressions’ paired key name.
Example
(tuple (name "blockstack") (id 1337))
xor
Syntax (xor i1 i2)
Input type:
int, int
Output type:
int
Returns the result of bitwise exclusive or’ing i1 with i2.
Example
(xor 1 2) ;; Returns 3
(xor 120 280) ;; Returns 352 view all
This file contains the reference for the Clarity language.
Block Properties
Supported types
Int type
Bool type
Buffer type
List type
Principal type
Tuple type
Optional type
Response type
Native variables
block-height
contract-name
tx-sender
Clarity function reference
* (multiply)
+ (add)
- (subtract)
/ (divide)
< (less than)
<= (less than or equal)
> (greater than)
>= (greater than or equal)
and
as-contract
begin
contract-call!
default-to
define-data-var
define-map
define-public
define-read-only
define
delete-entry!
eq?
err
expects!
expects-err!
fetch-contract-entry
fetch-entry
fetch-var
filter
fold
get-block-info
get
hash160
if
insert-entry!
is-none?
is-ok?
keccak256
let
list
map
mod
not
ok
or
pow
set-entry!
set-var!
sha256
tuple
xor
Block Properties
The get-block-info function fetches property details for a block at a specified block height. For example:
(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:
Property
Definition
header-hash
A 32-byte buffer containing the block hash.
burnchain-header-hash
A 32-byte buffer that contains the hash from the proof of burn.
vrf-seed
A 32-byte buffer containing the Verifiable Random Function (VRF) seed value used for the block.
time
An integer value containing that roughly corresponds to when the block was mined. This is a Unix epoch timestamp in seconds.
Warning: The time does not increase monotonically with each block. Block times are accurate only to within two hours. See BIP113 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.
Int type
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.
Bool type
Supports values of 'true or 'false.
Buffer type
Buffer types represent fixed-length byte buffers. Currently, the only way to construct a Buffer is using string literals, for example "alice.id" or hash160("bob.id")
All of the hash functions return buffers:
hash160 sha256 keccak256
The block properties header-hash, burnchain-header-hash, and vrf-seed are all buffers.
List type
Clarity supports 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.
Principal type
Clarity provides this primitive for checking whether or not the smart contract transaction was signed by a particular principal. Principals represent a spending entity and are roughly equivalent to a Stacks address. The principal’s signature is not checked by the smart contract, but by the virtual machine. A smart contract function can use the globally defined tx-sender variable to obtain the current principal.
Smart contracts may also be principals (represented by the smart contract’s identifier). However, there is no private key associated with the smart contract, and it cannot broadcast a signed transaction on the blockchain. A smart contract uses the special variable contract-name to refer to its own principal.
Tuple type
To support the use of named fields in keys and values, Clarity allows the construction of named tuples using a function (tuple ...), for example
(define imaginary-number-a (tuple (real 1) (i 2)))
(define imaginary-number-b (tuple (real 2) (i 3)))
This allows for creating named tuples on the fly, which is useful for data maps where the keys and values are themselves named tuples. Values in a given mapping are set or fetched using:
Function
Description
(fetch-entry map-name key-tuple)
Fetches the value associated with a given key in the map, or returns none if there is no such value.
(set-entry! map-name key-tuple value-tuple)
Sets the value of key-tuple in the data map
(insert-entry! map-name key-tuple value-tuple)
Sets the value of key-tuple in the data map if and only if an entry does not already exist.
(delete-entry! map-name key-tuple)
Deletes key-tuple from the data map.
To access a named value of a given tuple, the (get name tuple) function returns that item from the tuple.
Optional type
Represents an optional value. This is used in place of the typical usage of “null” values in other languages, and represents a type that can either be some value or none. Optional types are used as the return types of data-map functions.
Response type
Response types represent the result of a public function. Use this type to indicate and return data associated with the execution of the function. Also, the response should indicate whether the function error’ed (and therefore did not materialize any data in the database) or ran ok (in which case data materialized in the database).
Response types contain two subtypes – a response type in the event of ok (that is, a public function returns an integer code on success) and an err type (that is, a function returns a buffer on error).
Native variables
The Clarity language includes native variables you can use in your contract.
block-height
The height of a block in the Stacks blockchain. Block height is the number of blocks in the chain between any given block and the very first block in the blockchain. You can obtain a block-height via the get-block-info function.
contract-name
Represents the current contract.
tx-sender
Represents the current principal. This variable does not change during inter-contract calls. This 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. This enables a wide variety of applications, but it comes with some dangers for users of smart contracts. Static analysis of Clarity contracts guarantees the language allows clients to deduce which functions a given smart contract will ever call. Good clients should always warn users about any potential side effects of a given transaction.
Clarity function reference
* (multiply)
Syntax (* i1 i2...)
Input type:
int, ...
Output type:
int
Multiplies a variable number of integer inputs and returns the result. In the event of an overflow, throws a runtime error.
Example
(* 2 3) ;; Returns 6
(* 5 2) ;; Returns 10
(* 2 2 2) ;; Returns 8
+ (add)
Syntax (+ i1 i2...)
Input type:
int, ...
Output type:
int
Adds a variable number of integer inputs and returns the result. In the event of an overflow, throws a runtime error.
Example
(+ 1 2 3) ;; Returns 6
- (subtract)
Syntax (- i1 i2...)
Input type:
int, ...
Output type:
int
Subtracts a variable number of integer inputs and returns the result. In the event of an underflow, throws a runtime error.
Example
(- 2 1 1) ;; Returns 0
(- 0 3) ;; Returns -3
/ (divide)
Syntax (/ i1 i2...)
Input type:
int, ...
Output type:
int
Integer divides a variable number of integer inputs and returns the result. In the event of division by zero, throws a runtime error.
Example
(/ 2 3) ;; Returns 0
(/ 5 2) ;; Returns 2
(/ 4 2 2) ;; Returns 1
< (less than)
Syntax (< i1 i2)
Input type:
int, int
Output type:
bool
Compares two integers, returning true if i1 is less than i2 and false otherwise.
Example
(< 1 2) ;; Returns 'true
(< 5 2) ;; Returns 'false
<= (less than or equal)
Syntax (> i1 i2)
Input type:
int, int
Output type:
bool
Compares two integers, returning true if i1 is less than or equal to i2 and false otherwise.
Example
(<= 1 1) ;; Returns 'true
(<= 5 2) ;; Returns 'false
> (greater than)
Syntax (> i1 i2)
Input type:
int, int
Output type:
bool
Compares two integers, returning true if i1 is greater than i2 and false otherwise.
Example
(> 1 2) ;; Returns 'false
(> 5 2) ;; Returns 'true
>= (greater than or equal)
Syntax (>= i1 i2)
Input type:
int, int
Output type:
bool
Compares two integers, returning true if i1 is greater than or equal to i2 and false otherwise.
Example
(>= 1 1) ;; Returns 'true
(>= 5 2) ;; Returns 'true
and
Syntax (and b1 b2 ...)
Input type:
bool, ...
Output type:
bool
Returns true if all boolean inputs are true. Importantly, the supplied arguments are evaluated in-order and lazily. Lazy evaluation means that if one of the arguments returns false, the function short-circuits, and no subsequent arguments are evaluated.
Example
(and 'true 'false) ;; Returns 'false
(and (eq? (+ 1 2) 1) (eq? 4 4)) ;; Returns 'false
(and (eq? (+ 1 2) 3) (eq? 4 4)) ;; Returns 'true
as-contract
Syntax (as-contract expr)
Input type:
A
Output type:
A
The as-contract function switches the current context’s tx-sender value to the contract’s principal and executes expr with that context. It returns the resulting value of expr.
Example
(as-contract (print tx-sender)) ;; Returns 'CTcontract.name
begin
Syntax (begin expr1 expr2 expr3 ... expr-last)
Input type:
AnyType, ... A
Output type:
A
The begin function evaluates each of its input expressions, returning the return value of the last such expression.
Example
(begin (+ 1 2) 4 5) ;; Returns 5
contract-call!
Syntax (contract-call! contract-name function-name arg0 arg1 ...)
Input type:
ContractName, PublicFunctionName, Arg0, ...
Output type:
Response(A,B)
The contract-call! function executes the given public function of the given contract. You may not this function to call a public function defined in the current contract. If the public function returns err, any database changes resulting from calling contract-call! are aborted. If the function returns ok, database changes occurred.
Example
(contract-call! tokens transfer 'SZ2J6ZY48GV1EZ5V2V5RB9MP66SW86PYKKQ9H6DPR 19) ;; Returns (ok 1)
default-to
Syntax (default-to default-value option-value)
Input type:
A, Optional(A)
Output type:
A
The default-to function attempts to ‘unpack’ the second argument: if the argument is a (some ...) option, it returns the inner value of the option. If the second argument is a (none) value, default-to it returns the value of default-value.
Example
(default-to 0 (get id (fetch-entry names-map (tuple (name "blockstack"))))) ;; Returns 1337
(default-to 0 (get id (fetch-entry names-map (tuple (name "non-existant"))))) ;; Returns 0
define-data-var
Syntax (define-data-var var-name type value)
Input type:
VarName, TypeDefinition, Value
Output type:
Not Applicable
define-data-var is used to define a new persisted variable for use in a smart contract. Such variable are only modifiable by the current smart contract.
Persisted variable are defined with a type and a value.
Like other kinds of definition statements, define-data-var may only be used at the top level of a smart contract definition (i.e., you cannot put a define statement in the middle of a function body).
Example
(define-data-var size int 0)
(define (set-size (value int))
(set-var! size value))
(set-size 1)
(set-size 2)
define-map
Syntax (define-map map-name ((key-name-0 key-type-0) ...) ((val-name-0 val-type-0) ...))
Input type:
MapName, KeyTupleDefinition, MapTupleDefinition
Output type:
Not Applicable
define-map is used to define a new datamap for use in a smart contract. Such maps are only modifiable by the current smart contract.
Maps are defined with a key tuple type and value tuple type. These are defined using a list of name and type pairs, e.g., a key type might be ((id int)), which is a tuple with a single “id” field of type int.
Like other kinds of definition statements, define-map may only be used at the top level of a smart contract definition (i.e., you cannot put a define statement in the middle of a function body).
Example
(define-map squares ((x int)) ((square int)))
(define (add-entry (x int))
(insert-entry! squares ((x 2)) ((square (* x x)))))
(add-entry 1)
(add-entry 2)
(add-entry 3)
(add-entry 4)
(add-entry 5)
define-public
Syntax (define-public (function-name (arg-name-0 arg-type-0) (arg-name-1 arg-type-1) ...) function-body)
Input type:
MethodSignature, MethodBody
Output type:
Not Applicable
define-public is used to define a public function and transaction for a smart contract. Public functions are callable from other smart contracts and may be invoked directly by users by submitting a transaction to the Stacks blockchain.
Like other kinds of definition statements, define-public may only be used at the top level of a smart contract definition (i.e., you cannot put a define statement in the middle of a function body).
Public functions must return a ResponseType (using either ok or err). Any datamap modifications performed by a public function is aborted if the function returns an err type. Public functions may be invoked by other contracts via contract-call!.
Example
(define-public (hello-world (input int))
(begin (print (+ 2 input))
(ok input)))
define-read-only
Syntax (define-read-only (function-name (arg-name-0 arg-type-0) (arg-name-1 arg-type-1) ...) function-body)
Input type:
MethodSignature, MethodBody
Output type:
Not Applicable
define-read-only is used to define a public read-only function for a smart contract. Such functions are callable from other smart contracts.
Like other kinds of definition statements, define-read-only may only be used at the top level of a smart contract definition (i.e., you cannot put a define statement in the middle of a function body).
Read-only functions may return any type. However, read-only functions may not perform any datamap modifications, or call any functions which perform such modifications. This is enforced both during type checks and during the execution of the function. Public read-only functions may be invoked by other contracts via contract-call!.
Example
(define-read-only (just-return-one-hundred)
(* 10 10))
define
Syntax (define (function-name (arg-name-0 arg-type-0) (arg-name-1 arg-type-1) ...) function-body)
Input type:
MethodSignature, MethodBody
Output type:
Not Applicable
define is used to define private functions for a smart contract. Private functions may not be called from other smart contracts, nor may they be invoked directly by users. Instead, these functions may only be invoked by other functions defined in the same smart contract.
Like other kinds of definition statements, define may only be used at the top level of a smart contract definition (i.e., you cannot put a define statement in the middle of a function body).
Private functions may return any type.
Example
(define (max-of (i1 int) (i2 int))
(if (> i1 i2)
i1
i2))
(max-of 4 6) ;; returns 6
delete-entry!
Syntax (delete-entry! map-name key-tuple)
Input type:
MapName, Tuple
Output type:
bool
The delete-entry! function removes the value associated with the input key for the given map. If an item exists and is removed, the function returns true. If a value did not exist for this key in the data map, the function returns false.
Example
(delete-entry! names-map (tuple (name "blockstack"))) ;; Returns 'true
(delete-entry! names-map (tuple (name "blockstack"))) ;; Returns 'false
(delete-entry! names-map ((name "blockstack"))) ;; Same command, using a shorthand for constructing the tuple
eq?
Syntax (eq? v1 v2...)
Input type:
A, A, ...
Output type:
bool
Compares the inputted values, returning true if they are all equal. Note that unlike the (and ...) function, (eq? ...) will not short-circuit.
Example
(eq? 1 1) ;; Returns 'true
(eq? 1 'false) ;; Returns 'false
(eq? "abc" 234 234) ;; Returns 'false
err
Syntax (err value)
Input type:
A
Output type:
Response(A,B)
The err function constructs a response type from the input value. Use err for creating return values in public functions. An err value indicates that any database changes during the processing of the function should be rolled back.
Example
(err 'true) ;; Returns (err 'true)
expects!
Syntax (expects! option-input thrown-value)
Input type:
Optional(A) | Response(A,B), C
Output type:
A
The expects! function attempts to ‘unpack’ the first argument: if the argument is an option type, and the argument is a (some ...) option, expects! returns the inner value of the option. If the argument is a response type, and the argument is an (ok ...) response, expects! returns the inner value of the ok. If the supplied argument is either an (err ...) or a (none) value, expects! returns thrown-value from the current function and exits the current control-flow.
Example
(expects! (fetch-entry names-map (tuple (name "blockstack"))) (err 1)) ;; Returns (tuple (id 1337))
expects-err!
Syntax (expects-err! response-input thrown-value)
Input type:
Response(A,B), C
Output type:
B
The expects-err! function attempts to ‘unpack’ the first argument: if the argument is an (err ...) response, expects-err! returns the inner value of the err. If the supplied argument is an (ok ...) value, expects-err! returns thrown-value from the current function and exits the current control-flow.
Example
(expects-err! (err 1) 'false) ;; Returns 1
fetch-contract-entry
Syntax (fetch-contract-entry contract-name map-name key-tuple)
Input type:
ContractName, MapName, Tuple
Output type:
Optional(Tuple)
The fetch-contract-entry function looks up and returns an entry from a contract other than the current contract’s data map. The value is looked up using key-tuple. If there is no value associated with that key in the data map, the function returns a (none) option. Otherwise, it returns (some value).
Example
(expects! (fetch-contract-entry names-contract names-map (tuple (name "blockstack")) (err 1))) ;; Returns (tuple (id 1337))
(expects! (fetch-contract-entry names-contract names-map ((name "blockstack")) (err 1)));; Same command, using a shorthand for constructing the tuple
fetch-entry
Syntax (fetch-entry map-name key-tuple)
Input type:
MapName, Tuple
Output type:
Optional(Tuple)
The fetch-entry function looks up and returns an entry from a contract’s data map. The value is looked up using key-tuple. If there is no value associated with that key in the data map, the function returns a (none) option. Otherwise, it returns (some value)
Example
(expects! (fetch-entry names-map (tuple (name "blockstack"))) (err 1)) ;; Returns (tuple (id 1337))
(expects! (fetch-entry names-map ((name "blockstack"))) (err 1)) ;; Same command, using a shorthand for constructing the tuple
fetch-var
Syntax (fetch-var var-name)
Input type:
VarName
Output type:
A
The fetch-var function looks up and returns an entry from a contract’s data map. The value is looked up using var-name.
Example
(fetch-var cursor) ;; Returns cursor
filter
Syntax (filter func list)
Input type:
Function(A) -> bool, (list A)
Output type:
(list A)
The filter function applies the input function func to each element of the input list, and returns the same list with any elements removed for which the func returned false.
Example
(filter not (list true false true false)) ;; Returns (list false false)
fold
Syntax (fold func list initial-value)
Input type:
Function(A, B) -> B, (list A)
Output type:
B
The fold function applies the input function func to each element of the input list and the output of the previous application of the fold function. When invoked on the first list element, it uses the initial-value as the second input. fold returns the last value return by the successive applications.
Example
(fold * (list 2 2 2) 1) ;; Returns 8
(fold * (list 2 2 2) 0) ;; Returns 0
get-block-info
Syntax (get-block-info prop-name block-height-expr)
Input type:
BlockInfoPropertyName, BlockHeightInt
Output type:
buff | int
The get-block-info function fetches data for a block of the given block height. The value and type returned are determined by the specified BlockInfoPropertyName. If the provided BlockHeightInt does not correspond to an existing block, the function is aborted. The currently available property names are time, header-hash, burnchain-header-hash, and vrf-seed.
The time property returns an integer value of the block header time field. This is a Unix epoch timestamp in seconds which roughly corresponds to when the block was mined. Warning: this does not increase monotonically with each block and block times are accurate only to within two hours. See BIP113 for more information.
The header-hash, burnchain-header-hash, and vrf-seed properties return a 32-byte buffer.
Example
(get-block-info time 10) ;; Returns 1557860301
(get-block-info header-hash 2) ;; Returns 0x374708fff7719dd5979ec875d56cd2286f6d3cf7ec317a3b25632aab28ec37bb
(get-block-info vrf-seed 6) ;; Returns 0xf490de2920c8a35fabeb13208852aa28c76f9be9b03a4dd2b3c075f7a26923b4
get
Syntax (get key-name tuple)
Input type:
KeyName and Tuple | Optional(Tuple)
Output type:
AnyType
The get function fetches the value associated with a given key from the supplied typed tuple. If an Optional value is supplied as the inputted tuple, get returns an Optional type of the specified key in the tuple. If the supplied option is a (none) option, get returns (none).
Example
(get id (tuple (name "blockstack") (id 1337))) ;; Returns 1337
(get id (fetch-entry names-map (tuple (name "blockstack")))) ;; Returns (some 1337)
(get id (fetch-entry names-map (tuple (name "non-existent")))) ;; Returns (none)
hash160
Syntax (hash160 value)
Input type:
buff|int
Output type:
(buff 20)
The hash160 function computes RIPEMD160(SHA256(x)) of the inputted value. If an integer (128 bit) is supplied the hash is computed over the little-endian representation of the integer.
Example
(hash160 0) ;; Returns 0xe4352f72356db555721651aa612e00379167b30f
if
Syntax (if bool1 expr1 expr2)
Input type:
bool, A, A
Output type:
A
The if function admits a boolean argument and two expressions which must return the same type. In the case that the boolean input is true, the if function evaluates and returns expr1. If the boolean input is false, the if function evaluates and returns expr2.
Example
(if true 1 2) ;; Returns 1
(if (> 1 2) 1 2) ;; Returns 2
insert-entry!
Syntax (insert-entry! map-name key-tuple value-tuple)
Input type:
MapName, TupleA, TupleB
Output type:
bool
The insert-entry! function sets the value associated with the input key to the inputted value if and only if there is not already a value associated with the key in the map. If an insert occurs, the function returns true. If a value already existed for this key in the data map, the function returns false.
Example
(insert-entry! names-map (tuple (name "blockstack")) (tuple (id 1337))) ;; Returns 'true
(insert-entry! names-map (tuple (name "blockstack")) (tuple (id 1337))) ;; Returns 'false
(insert-entry! names-map ((name "blockstack")) ((id 1337))) ;; Same command, using a shorthand for constructing the tuple
is-none?
Syntax (is-none? value)
Input type:
Optional(A)
Output type:
bool
is-none? tests a supplied option value, returning true if the option value is (none), and false if it is a (some ...).
Example
(is-none? (get id (fetch-entry names-map (tuple (name "blockstack"))))) ;; Returns 'false
(is-none? (get id (fetch-entry names-map (tuple (name "non-existant"))))) ;; Returns 'true
is-ok?
Syntax (is-ok? value)
Input type:
Response(A,B)
Output type:
bool
is-ok? tests a supplied response value, returning true if the response was ok, and false if it was an err.
Example
(is-ok? (ok 1)) ;; Returns 'true
(is-ok? (err 1)) ;; Returns 'false
keccak256
Syntax (keccak256 value)
Input type:
buff|int
Output type:
(buff 32)
The keccak256 function computes KECCAK256(value) of the inputted value. Note that this differs from the NIST SHA-3 (that is, FIPS 202) standard. If an integer (128 bit) is supplied the hash is computed over the little-endian representation of the integer.
Example
(keccak256 0) ;; Returns 0xf490de2920c8a35fabeb13208852aa28c76f9be9b03a4dd2b3c075f7a26923b4
let
Syntax (let ((name1 expr1) (name2 expr2) ...) expr-body)
Input type:
((name2 AnyType) (name2 AnyType) ...), A
Output type:
A
The let function accepts a list of variable name and expression pairs, evaluating each expression and binding it to the corresponding variable name. The context created by this set of bindings is used for evaluating and return the value of expr-body.
Example
(let ((a 2) (b (+ 5 6 7))) (+ a b)) ;; Returns 20
list
Syntax (list expr1 expr2 expr3 ...)
Input type:
A, ...
Output type:
(list A)
The list function constructs a list composed of the inputted values. Each supplied value must be of the same type.
Example
(list (+ 1 2) 4 5) ;; Returns [3 4 5]
map
Syntax (map func list)
Input type:
Function(A) -> B, (list A)
Output type:
(list B)
The map function applies the input function func to each element of the input list, and outputs a list containing the outputs from those function applications.
Example
(map not (list true false true false)) ;; Returns 'false true false true
mod
Syntax (mod i1 i2)
Input type:
int, int
Output type:
int
Returns the integer remainder from integer dividing i1 by i2. In the event of a division by zero, throws a runtime error.
Example
(mod 2 3) ;; Returns 0
(mod 5 2) ;; Returns 1
(mod 7 1) ;; Returns 0
not
Syntax (not b1)
Input type:
bool
Output type:
bool
Returns the inverse of the boolean input.
Example
(not 'true) ;; Returns 'false
(not (eq? 1 2)) ;; Returns 'true
ok
Syntax (ok value)
Input type:
A
Output type:
Response(A,B)
The ok function constructs a response type from the input value. Use ok for creating return values in public functions. An ok value indicates that any database changes during the processing of the function should materialize.
Example
(ok 1) ;; Returns (ok 1)
or
Syntax (or b1 b2 ...)
Input type:
bool, ...
Output type:
bool
Returns true if any boolean inputs are true. Importantly, the supplied arguments are evaluated in-order and lazily. Lazy evaluation means that if one of the arguments returns false, the function short-circuits, and no subsequent arguments are evaluated.
Example
(or 'true 'false) ;; Returns 'true
(or (eq? (+ 1 2) 1) (eq? 4 4)) ;; Returns 'true
(or (eq? (+ 1 2) 1) (eq? 3 4)) ;; Returns 'false
(or (eq? (+ 1 2) 3) (eq? 4 4)) ;; Returns 'true
pow
Syntax (pow i1 i2)
Input type:
int, int
Output type:
int
Returns the result of raising i1 to the power of i2. In the event of an overflow, throws a runtime error.
Example
(pow 2 3) ;; Returns 8
(pow 2 2) ;; Returns 4
(pow 7 1) ;; Returns 7
Syntax (print expr)
Input type:
A
Output type:
A
The print function evaluates and returns its input expression. On Blockstack Core nodes configured for development (as opposed to production mining nodes), this function prints the resulting value to STDOUT (standard output).
Example
(print (+ 1 2 3)) ;; Returns 6
set-entry!
Syntax (set-entry! map-name key-tuple value-tuple)
Input type:
MapName, TupleA, TupleB
Output type:
bool
The set-entry! function sets the value associated with the input key to the inputted value. This function performs a blind update; whether or not a value is already associated with the key, the function overwrites that existing association.
Example
(set-entry! names-map (tuple (name "blockstack")) (tuple (id 1337))) ;; Returns 'true
(set-entry! names-map ((name "blockstack")) ((id 1337))) ;; Same command, using a shorthand for constructing the tuple
set-var!
Syntax (set-var! var-name expr1)
Input type:
VarName, AnyType
Output type:
bool
The set-var! function sets the value associated with the input variable to the inputted value.
Example
(set-var! cursor (+ cursor 1)) ;; Returns 'true
sha256
Syntax (sha256 value)
Input type:
buff|int
Output type:
(buff 32)
The sha256 function computes SHA256(x) of the inputted value. If an integer (128 bit) is supplied the hash is computed over the little-endian representation of the integer.
Example
(sha256 0) ;; Returns 0x374708fff7719dd5979ec875d56cd2286f6d3cf7ec317a3b25632aab28ec37bb
tuple
Syntax (tuple ((key0 expr0) (key1 expr1) ...))
Input type:
(list (KeyName AnyType))
Output type:
Tuple
The tuple function constructs a typed tuple from the supplied key and expression pairs. A get function can use typed tuples as input to select specific values from a given tuple. Key names may not appear multiple times in the same tuple definition. Supplied expressions are evaluated and associated with the expressions’ paired key name.
Example
(tuple (name "blockstack") (id 1337))
xor
Syntax (xor i1 i2)
Input type:
int, int
Output type:
int
Returns the result of bitwise exclusive or’ing i1 with i2.
Example
(xor 1 2) ;; Returns 3
(xor 120 280) ;; Returns 352
Quickstart for the SDK
Others • blockstack app store posted the article • 0 comments • 1556 views • 2019-06-28 01:40
About this tutorial and the prerequisites you need
Task 1: Generate an initial Clarity project
Task 2: Investigate the generated project
Task 3: Try to expand the contract
About this tutorial and the prerequisites you need
Note: 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.
For this tutorial, you will use npm to manage dependencies and scripts. The tutorial relies on the npm dependency manager. Before you begin, verify you have installed npm using the which command to verify.
$ which npm
/usr/local/bin/npm
If you don’t find npm in your system, install it.
You use npm to install Yeoman. Yeoman is a generic scaffolding system that helps users rapidly start new projects and streamline the maintenance of existing projects. Verify you have installed yo using the which command.
$ which yo
/usr/local/bin/yo
If you don’t have Yeoman, you can install it with the npm install -g yo command.
Task 1: Generate an initial Clarity project
The SDK uses Yeoman to generate a project scaffold — an initial set of directories and files.
1. Create a new directory for your project.
mkdir hello-clarity-sdk2. Change into your new project directory.cd hello-clarity-sdk3. Use the npm command to initialize a Clarity project.
npm init yo clarity-dev npx: installed 15 in 1.892s create package.json create .vscode/extensions.json ... Project created at /private/tmp/hello-clarity-sdk ✔ create-yo ok!Depending on your connection speed, it may take time to construct the scaffolding.
Task 2: Investigate the generated project
Your project should contain three directories:
The contracts directory contains a single file in sample/hello-world.clar file.
(define (hello-world)
"hello world")
(define (echo-number (val int))
val)
The contract exposes 2 rudimentary functions. The say-hi returns a hello world string. The increment-number: echos val.
The project also includes tests/hello-world.ts file. The test is written in Typescript. You can also write tests in Javascript.
import { Client, Provider, ProviderRegistry, Result } from "@blockstack/clarity";
import { assert } from "chai";
describe("hello world contract test suite", () => {
let helloWorldClient: Client;
let provider: Provider;
before(async () => {
provider = await ProviderRegistry.createProvider();
helloWorldClient = new Client("hello-world", "sample/hello-world", provider);
});
it("should have a valid syntax", async () => {
await helloWorldClient.checkContract();
});
describe("deploying an instance of the contract", () => {
before(async () => {
await helloWorldClient.deployContract();
});
it("should print hello world message", async () => {
const query = helloWorldClient.createQuery({ method: { name: "hello-world", args: } });
const receipt = await helloWorldClient.submitQuery(query);
const result = Result.unwrap(receipt);
const parsedResult = Buffer.from(result.replace("0x", ""), "hex").toString();
assert.equal(parsedResult, "hello world");
});
it("should echo number", async () => {
const query = helloWorldClient.createQuery({
method: { name: "echo-number", args: ["123"] }
});
const receipt = await helloWorldClient.submitQuery(query);
const result = Result.unwrap(receipt);
assert.equal(result, "123");
});
});
after(async () => {
await provider.close();
});
});
The hello-world.ts test file is a client that runs the hello-world.clar contract. Tests are critical for smart contracts as they are intended to manipulate assets and their ownership. These manipulations are irreversible within a blockchain. As you create a contracts, you should not be surprise if you end up spending more time and having more code in your tests than in your contracts directory. The tests/hello-world.ts file in the scaffold has the following content:
The first part of the test (lines 1 -10) sets up the test environment. It defines a Clarity provider and launches it (line 9). The Client instance contains a contract name and the path to the sample code. This test also checks the client (line 14) and then launches it (line 19), this is equivalent to running clarity-cli check with the command line. The remaining test code exercises the contract. Try running this test.
npm run test
> [email protected] test /private/tmp/hello-clarity-sdk
> mocha
hello world contract test suite
✓ should have a valid syntax
deploying an instance of the contract
✓ should print hello world message
✓ should echo number
3 passing (182ms)
In the next section, try your hand at expanding the hello-world.clar program.
Task 3: Try to expand the contract
In this task, you are challenged to expand the contents of the contracts/hello-world.clar file. Use your favorite editor and open the contracts/hello-world.clar file. If you use Visual Studio Code, you can install the Blockstack Clarity extension. The extension provides syntax coloration and some autocompletion.
Edit the hello-world.clar file.
;; Functions
(define (hello-world)
"hello world")
(define (echo-number (val int))
val)
Use the + function to create a increment-number-by-10 function.
answer:
;; Functions
(define (say-hi)
"hello world")
(define (increment-number (number int))
(+ 1 number))
(define (increment-number-by-10 (number int))
(+ 10 number))
Use the + and - function to create a decrement-number user-defined method.
answer: ;; Functions
(define (say-hi)
"hello world")
(define (increment-number (number int))
(+ 1 number))
(define (increment-number-by-10 (number int))
(+ 10 number))
(define (decrement-number (number int))
(- number 1))
Finally, try adding a counter variable and be sure to store it. Increment counter in your code and add a get-counter funtion to return the result. Here is a hint, you can add a var` to a contract by adding the following line (before the function):
```cl ;; Storage (define-data-var internal-value int 0)
answer:
;; Storage
(define-data-var counter int 0)
;; Functions
(define (say-hi)
"hello world")
(define (increment-number (number int))
(+ 1 number))
(define (increment-number-by-10 (number int))
(+ 10 number))
(define (decrement-number (number int))
(- number 1))
(define (increment-counter)
(set-var! counter (+ 1 counter)))
(define (get-counter)
(counter))
To review other, longer sample programs visit the ]clarity-js-sdk[/url] repository.
view all
About this tutorial and the prerequisites you need
Task 1: Generate an initial Clarity project
Task 2: Investigate the generated project
Task 3: Try to expand the contract
About this tutorial and the prerequisites you need
Note: 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.
For this tutorial, you will use npm to manage dependencies and scripts. The tutorial relies on the npm dependency manager. Before you begin, verify you have installed npm using the which command to verify.
$ which npm
/usr/local/bin/npm
If you don’t find npm in your system, install it.
You use npm to install Yeoman. Yeoman is a generic scaffolding system that helps users rapidly start new projects and streamline the maintenance of existing projects. Verify you have installed yo using the which command.
$ which yo
/usr/local/bin/yo
If you don’t have Yeoman, you can install it with the npm install -g yo command.
Task 1: Generate an initial Clarity project
The SDK uses Yeoman to generate a project scaffold — an initial set of directories and files.
1. Create a new directory for your project.
mkdir hello-clarity-sdk2. Change into your new project directory.
cd hello-clarity-sdk3. Use the npm command to initialize a Clarity project.
npm init yo clarity-dev npx: installed 15 in 1.892s create package.json create .vscode/extensions.json ... Project created at /private/tmp/hello-clarity-sdk ✔ create-yo ok!Depending on your connection speed, it may take time to construct the scaffolding.
Task 2: Investigate the generated project
Your project should contain three directories:

The contracts directory contains a single file in sample/hello-world.clar file.
(define (hello-world)
"hello world")
(define (echo-number (val int))
val)
The contract exposes 2 rudimentary functions. The say-hi returns a hello world string. The increment-number: echos val.
The project also includes tests/hello-world.ts file. The test is written in Typescript. You can also write tests in Javascript.
import { Client, Provider, ProviderRegistry, Result } from "@blockstack/clarity";
import { assert } from "chai";
describe("hello world contract test suite", () => {
let helloWorldClient: Client;
let provider: Provider;
before(async () => {
provider = await ProviderRegistry.createProvider();
helloWorldClient = new Client("hello-world", "sample/hello-world", provider);
});
it("should have a valid syntax", async () => {
await helloWorldClient.checkContract();
});
describe("deploying an instance of the contract", () => {
before(async () => {
await helloWorldClient.deployContract();
});
it("should print hello world message", async () => {
const query = helloWorldClient.createQuery({ method: { name: "hello-world", args: } });
const receipt = await helloWorldClient.submitQuery(query);
const result = Result.unwrap(receipt);
const parsedResult = Buffer.from(result.replace("0x", ""), "hex").toString();
assert.equal(parsedResult, "hello world");
});
it("should echo number", async () => {
const query = helloWorldClient.createQuery({
method: { name: "echo-number", args: ["123"] }
});
const receipt = await helloWorldClient.submitQuery(query);
const result = Result.unwrap(receipt);
assert.equal(result, "123");
});
});
after(async () => {
await provider.close();
});
});The hello-world.ts test file is a client that runs the hello-world.clar contract. Tests are critical for smart contracts as they are intended to manipulate assets and their ownership. These manipulations are irreversible within a blockchain. As you create a contracts, you should not be surprise if you end up spending more time and having more code in your tests than in your contracts directory. The tests/hello-world.ts file in the scaffold has the following content:
The first part of the test (lines 1 -10) sets up the test environment. It defines a Clarity provider and launches it (line 9). The Client instance contains a contract name and the path to the sample code. This test also checks the client (line 14) and then launches it (line 19), this is equivalent to running clarity-cli check with the command line. The remaining test code exercises the contract. Try running this test.
npm run test
> [email protected] test /private/tmp/hello-clarity-sdk
> mocha
hello world contract test suite
✓ should have a valid syntax
deploying an instance of the contract
✓ should print hello world message
✓ should echo number
3 passing (182ms)
In the next section, try your hand at expanding the hello-world.clar program.
Task 3: Try to expand the contract
In this task, you are challenged to expand the contents of the contracts/hello-world.clar file. Use your favorite editor and open the contracts/hello-world.clar file. If you use Visual Studio Code, you can install the Blockstack Clarity extension. The extension provides syntax coloration and some autocompletion.
Edit the hello-world.clar file.
;; Functions
(define (hello-world)
"hello world")
(define (echo-number (val int))
val)
Use the + function to create a increment-number-by-10 function.
answer:
;; Functions
(define (say-hi)
"hello world")
(define (increment-number (number int))
(+ 1 number))
(define (increment-number-by-10 (number int))
(+ 10 number))
Use the + and - function to create a decrement-number user-defined method.
answer:
;; FunctionsFinally, try adding a counter variable and be sure to store it. Increment counter in your code and add a get-counter funtion to return the result. Here is a hint, you can add a var` to a contract by adding the following line (before the function):
(define (say-hi)
"hello world")
(define (increment-number (number int))
(+ 1 number))
(define (increment-number-by-10 (number int))
(+ 10 number))
(define (decrement-number (number int))
(- number 1))
```cl ;; Storage (define-data-var internal-value int 0)
answer:
;; Storage
(define-data-var counter int 0)
;; Functions
(define (say-hi)
"hello world")
(define (increment-number (number int))
(+ 1 number))
(define (increment-number-by-10 (number int))
(+ 10 number))
(define (decrement-number (number int))
(- number 1))
(define (increment-counter)
(set-var! counter (+ 1 counter)))
(define (get-counter)
(counter))
To review other, longer sample programs visit the ]clarity-js-sdk[/url] repository.
clarity smart contract language - cli command line
Others • blockstack app store posted the article • 0 comments • 1385 views • 2019-06-28 01:27
You use the clarity-cli command to work with smart contracts within the Blockstack virtual environment. This command has the following subcommands:
initialize
mine_block
get_block_height
check
launch
eval
eval_raw
repl
execute
generate_address
initialize
clarity-cli initialize [vm-state.db]Initializes a local VM state database. If the database exists, this command throws an error.
mine_block
clarity-cli mine_block [block time] [vm-state.db]Simulates mining a new block.
get_block_height
clarity-cli get_block_height [vm-state.db]
Prints the simulated block height.
check
clarity-cli check [program-file.scm] (vm-state.db)
Type checks a potential contract definition.
launch
clarity-cli launch [contract-name] [contract-definition.scm] [vm-state.db]Launches a new contract in the local VM state database.
eval
clarity-cli eval [context-contract-name] (program.scm) [vm-state.db]Evaluates, in read-only mode, a program in a given contract context.
eval_raw
Type check and evaluate an expression for validity inside of a function’s source. It does not evaluate within a contract or database context.
repl
clarity-cli repl
Type check and evaluate expressions in a stdin/stdout loop.
execute
clarity-cli execute [vm-state.db] [contract-name] [public-function-name] [sender-address] [args...]
Executes a public function of a defined contract.
generate_address
clarity-cli generate_addressGenerates a random Stacks public address for testing purposes.
view all
You use the clarity-cli command to work with smart contracts within the Blockstack virtual environment. This command has the following subcommands:
initialize
mine_block
get_block_height
check
launch
eval
eval_raw
repl
execute
generate_address
initialize
clarity-cli initialize [vm-state.db]Initializes a local VM state database. If the database exists, this command throws an error.mine_block
clarity-cli mine_block [block time] [vm-state.db]Simulates mining a new block.
get_block_height
clarity-cli get_block_height [vm-state.db]Prints the simulated block height.
check
clarity-cli check [program-file.scm] (vm-state.db)Type checks a potential contract definition.
launch
clarity-cli launch [contract-name] [contract-definition.scm] [vm-state.db]Launches a new contract in the local VM state database.
eval
clarity-cli eval [context-contract-name] (program.scm) [vm-state.db]Evaluates, in read-only mode, a program in a given contract context.
eval_raw
Type check and evaluate an expression for validity inside of a function’s source. It does not evaluate within a contract or database context.
repl
clarity-cli replType check and evaluate expressions in a stdin/stdout loop.
execute
clarity-cli execute [vm-state.db] [contract-name] [public-function-name] [sender-address] [args...]
Executes a public function of a defined contract.
generate_address
clarity-cli generate_addressGenerates a random Stacks public address for testing purposes.
Hello Clarity tutorial
Others • blockstack app store posted the article • 0 comments • 1530 views • 2019-06-28 01:16
Before you begin (pre-requisites)
Task 1: Set up the test environment
Task 2: Review a simple Clarity program
Task 3: Initialize data-space and launch contracts
Task 4. Examine the SQLite database
Task 5: Execute a public function
Task 6: Spend tokens by registering a name
Before you begin (pre-requisites)
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 Docker installed on your workstation.
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 README file.
Task 1: Set up the test environment
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 and run the image on your local workstation.
1. Pull the Blockstack core clarity-developer-preview image from Docker Hub.
$ docker pull blockstack/blockstack-core:clarity-developer-preview2. Start the Blockstack Core test environment with a Bash shell.$ docker run -it -v $HOME/blockstack-dev-data:/data/ blockstack/blockstack-core:clarity-developer-preview bash
The 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.
root@f88368ba07b2:/src/blockstack-core# ls sample-programs/ names.clar tokens.clar
The sample programs directory contains two simple Clarity programs. Clarity code files have a .clar suffix.
4. Go ahead and display the contents of the tokens.clar program with the cat command.root@c28600552694:/src/blockstack-core# cat sample-programs/tokens.clarThe 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 line of the tokens.clar program contains a user-defined get-balance function.
(define (get-balance (account principal))
(default-to 0 (get balance (fetch-entry tokens (tuple (account account))))))
get-balance is a private function because it is constructed with the define 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..
(define (token-credit! (account principal) (tokens int))
(if (<= tokens 0)
(err "must move positive balance")
(let ((current-amount (get-balance account)))
(begin
(set-entry! tokens (tuple (account account))
(tuple (balance (+ tokens current-amount))))
(ok tokens)))))
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.
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 isa a globally defined variable that represents the the current principal.
(define-public (token-transfer (to principal) (amount int))
(let ((balance (get-balance tx-sender)))
(if (or (> amount balance) (<= amount 0))
(err "must transfer positive balance and possess funds")
(begin
(set-entry! tokens (tuple (account tx-sender))
(tuple (balance (- balance amount))))
(token-credit! to amount)))))
(define-public (mint! (amount int))
(let ((balance (get-balance tx-sender)))
(token-credit! tx-sender amount)))
(token-credit! 'SZ2J6ZY48GV1EZ5V2V5RB9MP66SW86PYKKQ9H6DPR 10000)
(token-credit! 'SM2J6ZY48GV1EZ5V2V5RB9MP66SW86PYKKQVX8X0G 300)
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 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 names.clar file.
cat names.clar
Which tokens.clar function is being called?
Task 3: Initialize data-space and launch contracts
1. In this task, you interact with the the contracts using the clarity-cli command line.
Initialize a new db database in the /data/ directory
# clarity-cli initialize /data/db
Database created
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.
2. Type check the names.clar contract.
# clarity-cli check sample-programs/names.clar /data/db
You should get an error:Type check error. NoSuchContract("tokens")This happens because the names.clar contract calls the tokens.clar contract, and that contract has not been created on the blockchain.
3. Type check the tokens.clar contract, it should pass a check as it does not use the contract-call function:
# clarity-cli check sample-programs/tokens.clar /data/db
Checks passed.When the check command executes successfully and exits with the stand UNIX 0 exit code.
4. Launch the tokens.clar contract.
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.
# clarity-cli launch 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.
5. Recheck the names.clar contract. # clarity-cli check sample-programs/names.clar /data/db
The program should pass validation because its dependency on tokens.clar is fulfilled.
6. Instantiate the names.clar contract as well.
# clarity-cli launch names sample-programs/names.clar /data/dbTask 4. Examine the SQLite database
The test environment uses a SQLite database to represent the blockchain. You initialized this database when you ran this earlier:
clarity-cli initialize /data/dbAs you work the contracts, data is added to the db database because you pass this database as a parameter, for example:
clarity-cli launch tokens sample-programs/tokens.clar /data/db
The database exists on your local workstation and persists through restarts of the container. You can use this database to examine the effects of your Clarity programs. The tables in the SQLite database are the following:
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 maps_table contains after you initialize the tokens contract.
sqlite> select * from maps_table;
1|tokens|tokens|{"Atom":{"TupleType":{"type_map":{"account":{"Atom":"PrincipalType"}}}}}|{"Atom":{"TupleType":{"type_map":{"balance":{"Atom":"IntType"}}}}}
sqlite>
Task 5: Execute a public function
In this section, you use the public mint! function in the tokens contract to mint some new tokens.
1. Use the clarity_cli command to create a demo address.
# clarity-cli generate_address SP26CHZZ26Q25WDD1CFJYSED169PS9HTNX445XKDG
2. Add the address to your environment.
# DEMO_ADDRESS=SP26CHZZ26Q25WDD1CFJYSED169PS9HTNX445XKDG
3. Get the current balance of your new address.
# echo "(get-balance '$DEMO_ADDRESS)" | clarity-cli eval tokens /data/db Program executed successfully! Output: 0
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.
4. Try minting some tokens and sending them to an address we’ll use for our demo.
# clarity-cli execute /data/db tokens mint! $DEMO_ADDRESS 100000
This executes the public mint! function defined in the tokens contract, sending 100000 tokens to you $DEMO_ADDRESS.
5. Use the clarity-cli eval command to check the result of this call.
# echo "(get-balance '$DEMO_ADDRESS)" | clarity-cli eval tokens /data/db Program executed successfully! Output: 100000
Task 6: Spend tokens by registering a name
Now, let’s register a name using the names.clar contract. Names are just integers in this sample contract, so you’ll register the name 10.
Compute the hash of the name we want to register.
You’ll salt the hash with the salt 8888:
# echo "(hash160 (xor 10 8888))" | clarity-cli eval names /data/db
Program executed successfully! Output:
0xb572fb1ce2e9665f1efd0994fe077b50c3a48fde
The value of the name hash is:
0xb572fb1ce2e9665f1efd0994fe077b50c3a48fde2. Preorder the name using the execute command:# clarity-cli execute /data/db names preorder $DEMO_ADDRESS 0xb572fb1ce2e9665f1efd0994fe077b50c3a48fde 1000
Transaction executed and committed. Returned: 0This 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).
3. Check the demo address’ new balance:# echo "(get-balance '$DEMO_ADDRESS)" | clarity-cli eval tokens /data/db
Program executed successfully! Output:
99000
4. Register the name by executing the register function:
# clarity-cli execute /data/db names register $DEMO_ADDRESS \'$DEMO_ADDRESS 10 8888
Transaction executed and committed. Returned: 0clarity-cli execute /data/db names register $DEMO_ADDRESS \'$DEMO_ADDRESS 10 8888
5. Lookup the “owner address” for the name:
# echo "(get owner (fetch-entry name-map (tuple (name 10))))" | clarity-cli eval names /data/db Program executed successfully! Output: (some 'SP26CHZZ26Q25WDD1CFJYSED169PS9HTNX445XKDG)
view all
Before you begin (pre-requisites)
Task 1: Set up the test environment
Task 2: Review a simple Clarity program
Task 3: Initialize data-space and launch contracts
Task 4. Examine the SQLite database
Task 5: Execute a public function
Task 6: Spend tokens by registering a name
Before you begin (pre-requisites)
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 Docker installed on your workstation.
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 README file.
Task 1: Set up the test environment
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 and run the image on your local workstation.
1. Pull the Blockstack core clarity-developer-preview image from Docker Hub.
$ docker pull blockstack/blockstack-core:clarity-developer-preview2. Start the Blockstack Core test environment with a Bash shell.
$ docker run -it -v $HOME/blockstack-dev-data:/data/ blockstack/blockstack-core:clarity-developer-preview bash
The 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.
root@f88368ba07b2:/src/blockstack-core# ls sample-programs/ names.clar tokens.clar
The sample programs directory contains two simple Clarity programs. Clarity code files have a .clar suffix.
4. Go ahead and display the contents of the tokens.clar program with the cat command.
root@c28600552694:/src/blockstack-core# cat sample-programs/tokens.clarThe 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 line of the tokens.clar program contains a user-defined get-balance function.
(define (get-balance (account principal))get-balance is a private function because it is constructed with the define 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.
(default-to 0 (get balance (fetch-entry tokens (tuple (account account))))))
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..
(define (token-credit! (account principal) (tokens int))
(if (<= tokens 0)
(err "must move positive balance")
(let ((current-amount (get-balance account)))
(begin
(set-entry! tokens (tuple (account account))
(tuple (balance (+ tokens current-amount))))
(ok tokens)))))
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.
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 isa a globally defined variable that represents the the current principal.
(define-public (token-transfer (to principal) (amount int))
(let ((balance (get-balance tx-sender)))
(if (or (> amount balance) (<= amount 0))
(err "must transfer positive balance and possess funds")
(begin
(set-entry! tokens (tuple (account tx-sender))
(tuple (balance (- balance amount))))
(token-credit! to amount)))))
(define-public (mint! (amount int))
(let ((balance (get-balance tx-sender)))
(token-credit! tx-sender amount)))
(token-credit! 'SZ2J6ZY48GV1EZ5V2V5RB9MP66SW86PYKKQ9H6DPR 10000)
(token-credit! 'SM2J6ZY48GV1EZ5V2V5RB9MP66SW86PYKKQVX8X0G 300)
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 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 names.clar file.
cat names.clar
Which tokens.clar function is being called?
Task 3: Initialize data-space and launch contracts
1. In this task, you interact with the the contracts using the clarity-cli command line.
Initialize a new db database in the /data/ directory
# clarity-cli initialize /data/dbYou 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.
Database created
2. Type check the names.clar contract.
# clarity-cli check sample-programs/names.clar /data/db
You should get an error:
Type check error. NoSuchContract("tokens")This happens because the names.clar contract calls the tokens.clar contract, and that contract has not been created on the blockchain.3. Type check the tokens.clar contract, it should pass a check as it does not use the contract-call function:
# clarity-cli check sample-programs/tokens.clar /data/dbWhen the check command executes successfully and exits with the stand UNIX 0 exit code.
Checks passed.
4. Launch the tokens.clar contract.
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.
# clarity-cli launch 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.
5. Recheck the names.clar contract.
# clarity-cli check sample-programs/names.clar /data/db
The program should pass validation because its dependency on tokens.clar is fulfilled.
6. Instantiate the names.clar contract as well.
# clarity-cli launch names sample-programs/names.clar /data/dbTask 4. Examine the SQLite database
The test environment uses a SQLite database to represent the blockchain. You initialized this database when you ran this earlier:
clarity-cli initialize /data/dbAs you work the contracts, data is added to the db database because you pass this database as a parameter, for example:
clarity-cli launch tokens sample-programs/tokens.clar /data/db
The database exists on your local workstation and persists through restarts of the container. You can use this database to examine the effects of your Clarity programs. The tables in the SQLite database are the following:

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 maps_table contains after you initialize the tokens contract.
sqlite> select * from maps_table;
1|tokens|tokens|{"Atom":{"TupleType":{"type_map":{"account":{"Atom":"PrincipalType"}}}}}|{"Atom":{"TupleType":{"type_map":{"balance":{"Atom":"IntType"}}}}}
sqlite>
Task 5: Execute a public function
In this section, you use the public mint! function in the tokens contract to mint some new tokens.
1. Use the clarity_cli command to create a demo address.
# clarity-cli generate_address SP26CHZZ26Q25WDD1CFJYSED169PS9HTNX445XKDG
2. Add the address to your environment.
# DEMO_ADDRESS=SP26CHZZ26Q25WDD1CFJYSED169PS9HTNX445XKDG
3. Get the current balance of your new address.
# echo "(get-balance '$DEMO_ADDRESS)" | clarity-cli eval tokens /data/db Program executed successfully! Output: 0
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.
4. Try minting some tokens and sending them to an address we’ll use for our demo.
# clarity-cli execute /data/db tokens mint! $DEMO_ADDRESS 100000
This executes the public mint! function defined in the tokens contract, sending 100000 tokens to you $DEMO_ADDRESS.
5. Use the clarity-cli eval command to check the result of this call.
# echo "(get-balance '$DEMO_ADDRESS)" | clarity-cli eval tokens /data/db Program executed successfully! Output: 100000
Task 6: Spend tokens by registering a name
Now, let’s register a name using the names.clar contract. Names are just integers in this sample contract, so you’ll register the name 10.
Compute the hash of the name we want to register.
You’ll salt the hash with the salt 8888:
# echo "(hash160 (xor 10 8888))" | clarity-cli eval names /data/db
Program executed successfully! Output:
0xb572fb1ce2e9665f1efd0994fe077b50c3a48fde
The value of the name hash is:
0xb572fb1ce2e9665f1efd0994fe077b50c3a48fde2. Preorder the name using the execute command:
# clarity-cli execute /data/db names preorder $DEMO_ADDRESS 0xb572fb1ce2e9665f1efd0994fe077b50c3a48fde 1000This 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).
Transaction executed and committed. Returned: 0
3. Check the demo address’ new balance:
# echo "(get-balance '$DEMO_ADDRESS)" | clarity-cli eval tokens /data/db
Program executed successfully! Output:
99000
4. Register the name by executing the register function:
# clarity-cli execute /data/db names register $DEMO_ADDRESS \'$DEMO_ADDRESS 10 88885. Lookup the “owner address” for the name:
Transaction executed and committed. Returned: 0clarity-cli execute /data/db names register $DEMO_ADDRESS \'$DEMO_ADDRESS 10 8888
# echo "(get owner (fetch-entry name-map (tuple (name 10))))" | clarity-cli eval names /data/db Program executed successfully! Output: (some 'SP26CHZZ26Q25WDD1CFJYSED169PS9HTNX445XKDG)
How to use Clarity smart contract language to define functions and data maps
Others • blockstack app store posted the article • 0 comments • 1722 views • 2019-06-28 00:59
define and define-public functions
define-read-only functions
define-map functions for data
List operations and functions
Intra-contract calls
Reading from other smart contracts
define and define-public functions
Functions specified via define-public statements are public functions. Functions without these designations, simple define statements, are private functions. You can run a contract’s public functions directly via the clarity-cli execute command line directly or from other contracts. You can use the clarity eval or clarity eval_raw commands to evaluate private functions via the command line.
Public functions return a Response type result. If the function returns an ok type, then the function call is considered valid, and any changes made to the blockchain state will be materialized. If the function returns an err type, it is considered invalid, and has no effect on the smart contract’s state.
For example, consider two functions, foo.A and bar.B where the foo.A function calls bar.B, the table below shows the data materialization that results from the possible combination of return values:
Defining of constants and functions are allowed for simplifying code using a define statement. However, these are purely syntactic. If a definition cannot be inlined, the contract is rejected as illegal. These definitions are also private, in that functions defined this way may only be called by other functions defined in the given smart contract.
define-read-only functions
Functions specified via define-read-only statements are public. Unlike functions created by define-public, functions created with define-read-only may return any type. However, define-read-only statements cannot perform state mutations. Any attempts to modify contract state by these functions or functions called by these functions result in an error.
define-map functions for data
Data within a smart contract’s data-space is stored within maps. These stores relate a typed-tuple to another typed-tuple (almost like a typed key-value store). As opposed to a table data structure, a map only associates a given key with exactly one value. A smart contract defines the data schema of a data map with the define-map function.
(define-map map-name ((key-name-0 key-type-0) ...) ((val-name-0 val-type-0) ...))
Clarity contracts can only call the define-map function in the top-level of the smart-contract (similar to define. This function accepts a name for the map, and a definition of the structure of the key and value types. Each of these is a list of (name, type) pairs. Types are either the values 'principal, 'integer, 'bool or the output of one of the hash calls which is an n-byte fixed-length buffer.
To support the use of named fields in keys and values, Clarity allows the construction of tuples using a function (tuple ((key0 expr0) (key1 expr1) ...)), for example:
(tuple (name "blockstack") (id 1337))
This allows for creating named tuples on the fly, which is useful for data maps where the keys and values are themselves named tuples. To access a named value of a given tuple, the function (get #name tuple) will return that item from the tuple.
The define-map interface, as described, disallows range-queries and queries-by-prefix on data maps. Within a smart contract function, you cannot iterate over an entire map. Values in a given mapping are set or fetched using the following functions:
Data maps make reasoning about functions easier. By inspecting a given function definition, it is clear which maps will be modified and, even within those maps, which keys are affected by a given invocation. Also, the interface of data maps ensures that the return types of map operations are fixed length; Fixed length returns is a requirement for static analysis of a contract’s runtime, costs, and other properties.
List operations and functions
Lists may be multi-dimensional. However, note that runtime admission checks on typed function-parameters and data-map functions like set-entry! are charged based on the maximal size of the multi-dimensional list.
You can call filter map and fold functions with user-defined functions (that is, functions defined with (define ...), (define-read-only ...), or (define-public ...)) or simple, native functions (for example, +, -, not).
Intra-contract calls
A smart contract may call functions from other smart contracts using a (contract-call!) function:(contract-call! contract-name function-name arg0 arg1 ...)
This function accepts a function name and the smart contract’s name as input. For example, to call the function token-transfer in the smart contract, you would use:
(contract-call! tokens token-transfer burn-address name-price))
For intra-contract calls dynamic dispatch is not supported. When a contract is launched, any contracts it depends on (calls) must exist. Additionally, no cycles may exist in the call graph of a smart contract. This prevents recursion (and re-entrancy bugs. A static analysis of the call graph detects such structures and they are rejected by the network.
A smart contract may not modify other smart contracts’ data directly; it can read data stored in those smart contracts’ maps. This read ability does not alter any confidentiality guarantees of Clarity. All data in a smart contract is inherently public, andis readable through querying the underlying database in any case.
Reading from other smart contracts
To read another contract’s data, use (fetch-contract-entry) function. This behaves identically to (fetch-entry), though it accepts a contract principal as an argument in addition to the map name:
(fetch-contract-entry
'contract-name
'map-name
'key-tuple) ;; value tuple or none
For example, you could do this:
(fetch-contract-entry
names
name-map
1) ;;returns owner principal of name
Just as with the (contract-call) function, the map name and contract principal arguments must be constants, specified at the time of publishing.
Finally, and importantly, the tx-sender variable does not change during inter-contract calls. This 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. This enables a wide variety of applications, but it comes with some dangers for users of smart contracts. However, the static analysis guarantees of Clarity allow clients to know a priori which functions a given smart contract will ever call. Good clients should always warn users about any potential side effects of a given transaction.
view all
define and define-public functions
define-read-only functions
define-map functions for data
List operations and functions
Intra-contract calls
Reading from other smart contracts
define and define-public functions
Functions specified via define-public statements are public functions. Functions without these designations, simple define statements, are private functions. You can run a contract’s public functions directly via the clarity-cli execute command line directly or from other contracts. You can use the clarity eval or clarity eval_raw commands to evaluate private functions via the command line.
Public functions return a Response type result. If the function returns an ok type, then the function call is considered valid, and any changes made to the blockchain state will be materialized. If the function returns an err type, it is considered invalid, and has no effect on the smart contract’s state.
For example, consider two functions, foo.A and bar.B where the foo.A function calls bar.B, the table below shows the data materialization that results from the possible combination of return values:

Defining of constants and functions are allowed for simplifying code using a define statement. However, these are purely syntactic. If a definition cannot be inlined, the contract is rejected as illegal. These definitions are also private, in that functions defined this way may only be called by other functions defined in the given smart contract.
define-read-only functions
Functions specified via define-read-only statements are public. Unlike functions created by define-public, functions created with define-read-only may return any type. However, define-read-only statements cannot perform state mutations. Any attempts to modify contract state by these functions or functions called by these functions result in an error.
define-map functions for data
Data within a smart contract’s data-space is stored within maps. These stores relate a typed-tuple to another typed-tuple (almost like a typed key-value store). As opposed to a table data structure, a map only associates a given key with exactly one value. A smart contract defines the data schema of a data map with the define-map function.
(define-map map-name ((key-name-0 key-type-0) ...) ((val-name-0 val-type-0) ...))
Clarity contracts can only call the define-map function in the top-level of the smart-contract (similar to define. This function accepts a name for the map, and a definition of the structure of the key and value types. Each of these is a list of (name, type) pairs. Types are either the values 'principal, 'integer, 'bool or the output of one of the hash calls which is an n-byte fixed-length buffer.
To support the use of named fields in keys and values, Clarity allows the construction of tuples using a function (tuple ((key0 expr0) (key1 expr1) ...)), for example:
(tuple (name "blockstack") (id 1337))
This allows for creating named tuples on the fly, which is useful for data maps where the keys and values are themselves named tuples. To access a named value of a given tuple, the function (get #name tuple) will return that item from the tuple.
The define-map interface, as described, disallows range-queries and queries-by-prefix on data maps. Within a smart contract function, you cannot iterate over an entire map. Values in a given mapping are set or fetched using the following functions:

Data maps make reasoning about functions easier. By inspecting a given function definition, it is clear which maps will be modified and, even within those maps, which keys are affected by a given invocation. Also, the interface of data maps ensures that the return types of map operations are fixed length; Fixed length returns is a requirement for static analysis of a contract’s runtime, costs, and other properties.
List operations and functions
Lists may be multi-dimensional. However, note that runtime admission checks on typed function-parameters and data-map functions like set-entry! are charged based on the maximal size of the multi-dimensional list.
You can call filter map and fold functions with user-defined functions (that is, functions defined with (define ...), (define-read-only ...), or (define-public ...)) or simple, native functions (for example, +, -, not).
Intra-contract calls
A smart contract may call functions from other smart contracts using a (contract-call!) function:
(contract-call! contract-name function-name arg0 arg1 ...)
This function accepts a function name and the smart contract’s name as input. For example, to call the function token-transfer in the smart contract, you would use:
(contract-call! tokens token-transfer burn-address name-price))
For intra-contract calls dynamic dispatch is not supported. When a contract is launched, any contracts it depends on (calls) must exist. Additionally, no cycles may exist in the call graph of a smart contract. This prevents recursion (and re-entrancy bugs. A static analysis of the call graph detects such structures and they are rejected by the network.
A smart contract may not modify other smart contracts’ data directly; it can read data stored in those smart contracts’ maps. This read ability does not alter any confidentiality guarantees of Clarity. All data in a smart contract is inherently public, andis readable through querying the underlying database in any case.
Reading from other smart contracts
To read another contract’s data, use (fetch-contract-entry) function. This behaves identically to (fetch-entry), though it accepts a contract principal as an argument in addition to the map name:
(fetch-contract-entry
'contract-name
'map-name
'key-tuple) ;; value tuple or none
For example, you could do this:
(fetch-contract-entry
names
name-map
1) ;;returns owner principal of name
Just as with the (contract-call) function, the map name and contract principal arguments must be constants, specified at the time of publishing.
Finally, and importantly, the tx-sender variable does not change during inter-contract calls. This 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. This enables a wide variety of applications, but it comes with some dangers for users of smart contracts. However, the static analysis guarantees of Clarity allow clients to know a priori which functions a given smart contract will ever call. Good clients should always warn users about any potential side effects of a given transaction.
Principals-a Clarity (smart contract language for blockstack dapps)native type
Others • blockstack app store posted the article • 0 comments • 1497 views • 2019-06-28 00:49
Principals and tx-sender
A principal is represented by a public-key hash or multi-signature Stacks address. Assets in Clarity and the Stacks blockchain are “owned” by objects of the principal type; put another way, principal object types may own an asset.
A given principal operates on its assets by issuing a signed transaction on the Stacks blockchain. A Clarity contract can use a globally defined tx-sender variable to obtain the current principal.
The following user-defined function transfers an asset, in this case, tokens, between two principals:
(define (transfer! (sender principal) (recipient principal) (amount int))
(if (and
(not (eq? sender recipient))
(debit-balance! sender amount)
(credit-balance! recipient amount))
'true
'false))
The principal’s signature is not checked by the smart contract, but by the virtual machine.
Smart contracts as principals
Smart contracts themselves are principals and are represented by the smart contract’s identifier. You create the identifier when you launch the contract, for example, the contract identifier here is hanomine.
clarity-cli launch hanomine /data/hano.clar /data/db
A smart contract may use the special variable contract-name to refer to its own principal.
To allow smart contracts to operate on assets it owns, smart contracts may use the special (as-contract expr) function. This function executes the expression (passed as an argument) with the tx-sender set to the contract’s principal, rather than the current sender. The as-contract function returns the value of the provided expression.
For example, a smart contract that implements something like a “token faucet” could be implemented as so:
(define-public (claim-from-faucet)
(if (is-none? (fetch-entry claimed-before (tuple (sender tx-sender))))
(let ((requester tx-sender)) ;; set a local variable requester = tx-sender
(begin
(insert-entry! claimed-before (tuple (sender requester)) (tuple (claimed 'true)))
(as-contract (stacks-transfer! requester 1)))))
(err 1))
In this example, the public function claim-from-faucet:
Checks if the sender has claimed from the faucet before.Assigns the tx sender to a requester variable.Adds an entry to the tracking map.Uses as-contract to send 1 microstack
Contract writers can use the primitive function is-contract? to determine whether a given principal corresponds to a smart contract.
Unlike other principals, there is no private key associated with a smart contract. As it lacks a private key, a Clarity smart contract cannot broadcast a signed transaction on the blockchain.
view all
Principals and tx-sender
A principal is represented by a public-key hash or multi-signature Stacks address. Assets in Clarity and the Stacks blockchain are “owned” by objects of the principal type; put another way, principal object types may own an asset.
A given principal operates on its assets by issuing a signed transaction on the Stacks blockchain. A Clarity contract can use a globally defined tx-sender variable to obtain the current principal.
The following user-defined function transfers an asset, in this case, tokens, between two principals:
(define (transfer! (sender principal) (recipient principal) (amount int))
(if (and
(not (eq? sender recipient))
(debit-balance! sender amount)
(credit-balance! recipient amount))
'true
'false))
The principal’s signature is not checked by the smart contract, but by the virtual machine.
Smart contracts as principals
Smart contracts themselves are principals and are represented by the smart contract’s identifier. You create the identifier when you launch the contract, for example, the contract identifier here is hanomine.
clarity-cli launch hanomine /data/hano.clar /data/db
A smart contract may use the special variable contract-name to refer to its own principal.
To allow smart contracts to operate on assets it owns, smart contracts may use the special (as-contract expr) function. This function executes the expression (passed as an argument) with the tx-sender set to the contract’s principal, rather than the current sender. The as-contract function returns the value of the provided expression.
For example, a smart contract that implements something like a “token faucet” could be implemented as so:
(define-public (claim-from-faucet)
(if (is-none? (fetch-entry claimed-before (tuple (sender tx-sender))))
(let ((requester tx-sender)) ;; set a local variable requester = tx-sender
(begin
(insert-entry! claimed-before (tuple (sender requester)) (tuple (claimed 'true)))
(as-contract (stacks-transfer! requester 1)))))
(err 1))
In this example, the public function claim-from-faucet:
- Checks if the sender has claimed from the faucet before.
- Assigns the tx sender to a requester variable.
- Adds an entry to the tracking map.
- Uses as-contract to send 1 microstack
Contract writers can use the primitive function is-contract? to determine whether a given principal corresponds to a smart contract.
Unlike other principals, there is no private key associated with a smart contract. As it lacks a private key, a Clarity smart contract cannot broadcast a signed transaction on the blockchain.
Clarity-Blockstack smart contract language tutorials and docs
Others • blockstack app store posted the article • 0 comments • 1757 views • 2019-06-28 00:38
Who should use smart contracts?
Language and program design
The coding environment
Basic building blocks of Clarity contracts
hello-world example
Language rules and limitations
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.
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.
Not every application requires smart contracts. If you are not sure or are new to smart contracts concepts, you should read ]a good general explanation of smart contracts[/url] before working with Clarity.
Language and program design
Clarity differs from most other smart contract languages in two essential ways:
The language is not intended to be compiled.The language is not Turing complete.
These differences allow for static analysis of programs to determine properties like runtime cost and data usage.
A Clarity smart contract is composed of two parts — 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.
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.
The coding environment
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. 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.
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-sender10000SZ2J6ZY48GV1EZ5V2V5RB9MP66SW86PYKKQ9H6DPR
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.
;; 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.
(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:
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.
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:
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:
The only atomic types are booleans, integers, fixed length buffers, and principalsRecursion is illegal and there is no lambda function.Looping may only be performed via map, filter, or foldThere 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.
view all
Who should use smart contracts?
Language and program design
The coding environment
Basic building blocks of Clarity contracts
hello-world example
Language rules and limitations
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.
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.
Not every application requires smart contracts. If you are not sure or are new to smart contracts concepts, you should read ]a good general explanation of smart contracts[/url] before working with Clarity.
Language and program design
Clarity differs from most other smart contract languages in two essential ways:
- The language is not intended to be compiled.
- The language is not Turing complete.
These differences allow for static analysis of programs to determine properties like runtime cost and data usage.
A Clarity smart contract is composed of two parts — 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.
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.
The coding environment
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. 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.
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.
;; 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.
(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:
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.
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:
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:
- The only atomic types are booleans, integers, fixed length buffers, and principals
- Recursion is illegal and there is no lambda function.
- Looping may only be performed via map, filter, or fold
- 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.
Clarity- smart contract language reference
Others • blockstack app store posted the article • 0 comments • 1606 views • 2019-06-28 01:45
This file contains the reference for the Clarity language.
Block Properties
Supported types
Int type
Bool type
Buffer type
List type
Principal type
Tuple type
Optional type
Response type
Native variables
block-height
contract-name
tx-sender
Clarity function reference
* (multiply)
+ (add)
- (subtract)
/ (divide)
< (less than)
<= (less than or equal)
> (greater than)
>= (greater than or equal)
and
as-contract
begin
contract-call!
default-to
define-data-var
define-map
define-public
define-read-only
define
delete-entry!
eq?
err
expects!
expects-err!
fetch-contract-entry
fetch-entry
fetch-var
filter
fold
get-block-info
get
hash160
if
insert-entry!
is-none?
is-ok?
keccak256
let
list
map
mod
not
ok
or
pow
set-entry!
set-var!
sha256
tuple
xor
Block Properties
The get-block-info function fetches property details for a block at a specified block height. For example:
(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:
Property
Definition
header-hash
A 32-byte buffer containing the block hash.
burnchain-header-hash
A 32-byte buffer that contains the hash from the proof of burn.
vrf-seed
A 32-byte buffer containing the Verifiable Random Function (VRF) seed value used for the block.
time
An integer value containing that roughly corresponds to when the block was mined. This is a Unix epoch timestamp in seconds.
Warning: The time does not increase monotonically with each block. Block times are accurate only to within two hours. See BIP113 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.
Int type
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.
Bool type
Supports values of 'true or 'false.
Buffer type
Buffer types represent fixed-length byte buffers. Currently, the only way to construct a Buffer is using string literals, for example "alice.id" or hash160("bob.id")
All of the hash functions return buffers:
hash160 sha256 keccak256
The block properties header-hash, burnchain-header-hash, and vrf-seed are all buffers.
List type
Clarity supports 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.
Principal type
Clarity provides this primitive for checking whether or not the smart contract transaction was signed by a particular principal. Principals represent a spending entity and are roughly equivalent to a Stacks address. The principal’s signature is not checked by the smart contract, but by the virtual machine. A smart contract function can use the globally defined tx-sender variable to obtain the current principal.
Smart contracts may also be principals (represented by the smart contract’s identifier). However, there is no private key associated with the smart contract, and it cannot broadcast a signed transaction on the blockchain. A smart contract uses the special variable contract-name to refer to its own principal.
Tuple type
To support the use of named fields in keys and values, Clarity allows the construction of named tuples using a function (tuple ...), for example
(define imaginary-number-a (tuple (real 1) (i 2)))
(define imaginary-number-b (tuple (real 2) (i 3)))
This allows for creating named tuples on the fly, which is useful for data maps where the keys and values are themselves named tuples. Values in a given mapping are set or fetched using:
Function
Description
(fetch-entry map-name key-tuple)
Fetches the value associated with a given key in the map, or returns none if there is no such value.
(set-entry! map-name key-tuple value-tuple)
Sets the value of key-tuple in the data map
(insert-entry! map-name key-tuple value-tuple)
Sets the value of key-tuple in the data map if and only if an entry does not already exist.
(delete-entry! map-name key-tuple)
Deletes key-tuple from the data map.
To access a named value of a given tuple, the (get name tuple) function returns that item from the tuple.
Optional type
Represents an optional value. This is used in place of the typical usage of “null” values in other languages, and represents a type that can either be some value or none. Optional types are used as the return types of data-map functions.
Response type
Response types represent the result of a public function. Use this type to indicate and return data associated with the execution of the function. Also, the response should indicate whether the function error’ed (and therefore did not materialize any data in the database) or ran ok (in which case data materialized in the database).
Response types contain two subtypes – a response type in the event of ok (that is, a public function returns an integer code on success) and an err type (that is, a function returns a buffer on error).
Native variables
The Clarity language includes native variables you can use in your contract.
block-height
The height of a block in the Stacks blockchain. Block height is the number of blocks in the chain between any given block and the very first block in the blockchain. You can obtain a block-height via the get-block-info function.
contract-name
Represents the current contract.
tx-sender
Represents the current principal. This variable does not change during inter-contract calls. This 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. This enables a wide variety of applications, but it comes with some dangers for users of smart contracts. Static analysis of Clarity contracts guarantees the language allows clients to deduce which functions a given smart contract will ever call. Good clients should always warn users about any potential side effects of a given transaction.
Clarity function reference
* (multiply)
Syntax (* i1 i2...)
Input type:
int, ...
Output type:
int
Multiplies a variable number of integer inputs and returns the result. In the event of an overflow, throws a runtime error.
Example
(* 2 3) ;; Returns 6
(* 5 2) ;; Returns 10
(* 2 2 2) ;; Returns 8
+ (add)
Syntax (+ i1 i2...)
Input type:
int, ...
Output type:
int
Adds a variable number of integer inputs and returns the result. In the event of an overflow, throws a runtime error.
Example
(+ 1 2 3) ;; Returns 6
- (subtract)
Syntax (- i1 i2...)
Input type:
int, ...
Output type:
int
Subtracts a variable number of integer inputs and returns the result. In the event of an underflow, throws a runtime error.
Example
(- 2 1 1) ;; Returns 0
(- 0 3) ;; Returns -3
/ (divide)
Syntax (/ i1 i2...)
Input type:
int, ...
Output type:
int
Integer divides a variable number of integer inputs and returns the result. In the event of division by zero, throws a runtime error.
Example
(/ 2 3) ;; Returns 0
(/ 5 2) ;; Returns 2
(/ 4 2 2) ;; Returns 1
< (less than)
Syntax (< i1 i2)
Input type:
int, int
Output type:
bool
Compares two integers, returning true if i1 is less than i2 and false otherwise.
Example
(< 1 2) ;; Returns 'true
(< 5 2) ;; Returns 'false
<= (less than or equal)
Syntax (> i1 i2)
Input type:
int, int
Output type:
bool
Compares two integers, returning true if i1 is less than or equal to i2 and false otherwise.
Example
(<= 1 1) ;; Returns 'true
(<= 5 2) ;; Returns 'false
> (greater than)
Syntax (> i1 i2)
Input type:
int, int
Output type:
bool
Compares two integers, returning true if i1 is greater than i2 and false otherwise.
Example
(> 1 2) ;; Returns 'false
(> 5 2) ;; Returns 'true
>= (greater than or equal)
Syntax (>= i1 i2)
Input type:
int, int
Output type:
bool
Compares two integers, returning true if i1 is greater than or equal to i2 and false otherwise.
Example
(>= 1 1) ;; Returns 'true
(>= 5 2) ;; Returns 'true
and
Syntax (and b1 b2 ...)
Input type:
bool, ...
Output type:
bool
Returns true if all boolean inputs are true. Importantly, the supplied arguments are evaluated in-order and lazily. Lazy evaluation means that if one of the arguments returns false, the function short-circuits, and no subsequent arguments are evaluated.
Example
(and 'true 'false) ;; Returns 'false
(and (eq? (+ 1 2) 1) (eq? 4 4)) ;; Returns 'false
(and (eq? (+ 1 2) 3) (eq? 4 4)) ;; Returns 'true
as-contract
Syntax (as-contract expr)
Input type:
A
Output type:
A
The as-contract function switches the current context’s tx-sender value to the contract’s principal and executes expr with that context. It returns the resulting value of expr.
Example
(as-contract (print tx-sender)) ;; Returns 'CTcontract.name
begin
Syntax (begin expr1 expr2 expr3 ... expr-last)
Input type:
AnyType, ... A
Output type:
A
The begin function evaluates each of its input expressions, returning the return value of the last such expression.
Example
(begin (+ 1 2) 4 5) ;; Returns 5
contract-call!
Syntax (contract-call! contract-name function-name arg0 arg1 ...)
Input type:
ContractName, PublicFunctionName, Arg0, ...
Output type:
Response(A,B)
The contract-call! function executes the given public function of the given contract. You may not this function to call a public function defined in the current contract. If the public function returns err, any database changes resulting from calling contract-call! are aborted. If the function returns ok, database changes occurred.
Example
(contract-call! tokens transfer 'SZ2J6ZY48GV1EZ5V2V5RB9MP66SW86PYKKQ9H6DPR 19) ;; Returns (ok 1)
default-to
Syntax (default-to default-value option-value)
Input type:
A, Optional(A)
Output type:
A
The default-to function attempts to ‘unpack’ the second argument: if the argument is a (some ...) option, it returns the inner value of the option. If the second argument is a (none) value, default-to it returns the value of default-value.
Example
(default-to 0 (get id (fetch-entry names-map (tuple (name "blockstack"))))) ;; Returns 1337
(default-to 0 (get id (fetch-entry names-map (tuple (name "non-existant"))))) ;; Returns 0
define-data-var
Syntax (define-data-var var-name type value)
Input type:
VarName, TypeDefinition, Value
Output type:
Not Applicable
define-data-var is used to define a new persisted variable for use in a smart contract. Such variable are only modifiable by the current smart contract.
Persisted variable are defined with a type and a value.
Like other kinds of definition statements, define-data-var may only be used at the top level of a smart contract definition (i.e., you cannot put a define statement in the middle of a function body).
Example
(define-data-var size int 0)
(define (set-size (value int))
(set-var! size value))
(set-size 1)
(set-size 2)
define-map
Syntax (define-map map-name ((key-name-0 key-type-0) ...) ((val-name-0 val-type-0) ...))
Input type:
MapName, KeyTupleDefinition, MapTupleDefinition
Output type:
Not Applicable
define-map is used to define a new datamap for use in a smart contract. Such maps are only modifiable by the current smart contract.
Maps are defined with a key tuple type and value tuple type. These are defined using a list of name and type pairs, e.g., a key type might be ((id int)), which is a tuple with a single “id” field of type int.
Like other kinds of definition statements, define-map may only be used at the top level of a smart contract definition (i.e., you cannot put a define statement in the middle of a function body).
Example
(define-map squares ((x int)) ((square int)))
(define (add-entry (x int))
(insert-entry! squares ((x 2)) ((square (* x x)))))
(add-entry 1)
(add-entry 2)
(add-entry 3)
(add-entry 4)
(add-entry 5)
define-public
Syntax (define-public (function-name (arg-name-0 arg-type-0) (arg-name-1 arg-type-1) ...) function-body)
Input type:
MethodSignature, MethodBody
Output type:
Not Applicable
define-public is used to define a public function and transaction for a smart contract. Public functions are callable from other smart contracts and may be invoked directly by users by submitting a transaction to the Stacks blockchain.
Like other kinds of definition statements, define-public may only be used at the top level of a smart contract definition (i.e., you cannot put a define statement in the middle of a function body).
Public functions must return a ResponseType (using either ok or err). Any datamap modifications performed by a public function is aborted if the function returns an err type. Public functions may be invoked by other contracts via contract-call!.
Example
(define-public (hello-world (input int))
(begin (print (+ 2 input))
(ok input)))
define-read-only
Syntax (define-read-only (function-name (arg-name-0 arg-type-0) (arg-name-1 arg-type-1) ...) function-body)
Input type:
MethodSignature, MethodBody
Output type:
Not Applicable
define-read-only is used to define a public read-only function for a smart contract. Such functions are callable from other smart contracts.
Like other kinds of definition statements, define-read-only may only be used at the top level of a smart contract definition (i.e., you cannot put a define statement in the middle of a function body).
Read-only functions may return any type. However, read-only functions may not perform any datamap modifications, or call any functions which perform such modifications. This is enforced both during type checks and during the execution of the function. Public read-only functions may be invoked by other contracts via contract-call!.
Example
(define-read-only (just-return-one-hundred)
(* 10 10))
define
Syntax (define (function-name (arg-name-0 arg-type-0) (arg-name-1 arg-type-1) ...) function-body)
Input type:
MethodSignature, MethodBody
Output type:
Not Applicable
define is used to define private functions for a smart contract. Private functions may not be called from other smart contracts, nor may they be invoked directly by users. Instead, these functions may only be invoked by other functions defined in the same smart contract.
Like other kinds of definition statements, define may only be used at the top level of a smart contract definition (i.e., you cannot put a define statement in the middle of a function body).
Private functions may return any type.
Example
(define (max-of (i1 int) (i2 int))
(if (> i1 i2)
i1
i2))
(max-of 4 6) ;; returns 6
delete-entry!
Syntax (delete-entry! map-name key-tuple)
Input type:
MapName, Tuple
Output type:
bool
The delete-entry! function removes the value associated with the input key for the given map. If an item exists and is removed, the function returns true. If a value did not exist for this key in the data map, the function returns false.
Example
(delete-entry! names-map (tuple (name "blockstack"))) ;; Returns 'true
(delete-entry! names-map (tuple (name "blockstack"))) ;; Returns 'false
(delete-entry! names-map ((name "blockstack"))) ;; Same command, using a shorthand for constructing the tuple
eq?
Syntax (eq? v1 v2...)
Input type:
A, A, ...
Output type:
bool
Compares the inputted values, returning true if they are all equal. Note that unlike the (and ...) function, (eq? ...) will not short-circuit.
Example
(eq? 1 1) ;; Returns 'true
(eq? 1 'false) ;; Returns 'false
(eq? "abc" 234 234) ;; Returns 'false
err
Syntax (err value)
Input type:
A
Output type:
Response(A,B)
The err function constructs a response type from the input value. Use err for creating return values in public functions. An err value indicates that any database changes during the processing of the function should be rolled back.
Example
(err 'true) ;; Returns (err 'true)
expects!
Syntax (expects! option-input thrown-value)
Input type:
Optional(A) | Response(A,B), C
Output type:
A
The expects! function attempts to ‘unpack’ the first argument: if the argument is an option type, and the argument is a (some ...) option, expects! returns the inner value of the option. If the argument is a response type, and the argument is an (ok ...) response, expects! returns the inner value of the ok. If the supplied argument is either an (err ...) or a (none) value, expects! returns thrown-value from the current function and exits the current control-flow.
Example
(expects! (fetch-entry names-map (tuple (name "blockstack"))) (err 1)) ;; Returns (tuple (id 1337))
expects-err!
Syntax (expects-err! response-input thrown-value)
Input type:
Response(A,B), C
Output type:
B
The expects-err! function attempts to ‘unpack’ the first argument: if the argument is an (err ...) response, expects-err! returns the inner value of the err. If the supplied argument is an (ok ...) value, expects-err! returns thrown-value from the current function and exits the current control-flow.
Example
(expects-err! (err 1) 'false) ;; Returns 1
fetch-contract-entry
Syntax (fetch-contract-entry contract-name map-name key-tuple)
Input type:
ContractName, MapName, Tuple
Output type:
Optional(Tuple)
The fetch-contract-entry function looks up and returns an entry from a contract other than the current contract’s data map. The value is looked up using key-tuple. If there is no value associated with that key in the data map, the function returns a (none) option. Otherwise, it returns (some value).
Example
(expects! (fetch-contract-entry names-contract names-map (tuple (name "blockstack")) (err 1))) ;; Returns (tuple (id 1337))
(expects! (fetch-contract-entry names-contract names-map ((name "blockstack")) (err 1)));; Same command, using a shorthand for constructing the tuple
fetch-entry
Syntax (fetch-entry map-name key-tuple)
Input type:
MapName, Tuple
Output type:
Optional(Tuple)
The fetch-entry function looks up and returns an entry from a contract’s data map. The value is looked up using key-tuple. If there is no value associated with that key in the data map, the function returns a (none) option. Otherwise, it returns (some value)
Example
(expects! (fetch-entry names-map (tuple (name "blockstack"))) (err 1)) ;; Returns (tuple (id 1337))
(expects! (fetch-entry names-map ((name "blockstack"))) (err 1)) ;; Same command, using a shorthand for constructing the tuple
fetch-var
Syntax (fetch-var var-name)
Input type:
VarName
Output type:
A
The fetch-var function looks up and returns an entry from a contract’s data map. The value is looked up using var-name.
Example
(fetch-var cursor) ;; Returns cursor
filter
Syntax (filter func list)
Input type:
Function(A) -> bool, (list A)
Output type:
(list A)
The filter function applies the input function func to each element of the input list, and returns the same list with any elements removed for which the func returned false.
Example
(filter not (list true false true false)) ;; Returns (list false false)
fold
Syntax (fold func list initial-value)
Input type:
Function(A, B) -> B, (list A)
Output type:
B
The fold function applies the input function func to each element of the input list and the output of the previous application of the fold function. When invoked on the first list element, it uses the initial-value as the second input. fold returns the last value return by the successive applications.
Example
(fold * (list 2 2 2) 1) ;; Returns 8
(fold * (list 2 2 2) 0) ;; Returns 0
get-block-info
Syntax (get-block-info prop-name block-height-expr)
Input type:
BlockInfoPropertyName, BlockHeightInt
Output type:
buff | int
The get-block-info function fetches data for a block of the given block height. The value and type returned are determined by the specified BlockInfoPropertyName. If the provided BlockHeightInt does not correspond to an existing block, the function is aborted. The currently available property names are time, header-hash, burnchain-header-hash, and vrf-seed.
The time property returns an integer value of the block header time field. This is a Unix epoch timestamp in seconds which roughly corresponds to when the block was mined. Warning: this does not increase monotonically with each block and block times are accurate only to within two hours. See BIP113 for more information.
The header-hash, burnchain-header-hash, and vrf-seed properties return a 32-byte buffer.
Example
(get-block-info time 10) ;; Returns 1557860301
(get-block-info header-hash 2) ;; Returns 0x374708fff7719dd5979ec875d56cd2286f6d3cf7ec317a3b25632aab28ec37bb
(get-block-info vrf-seed 6) ;; Returns 0xf490de2920c8a35fabeb13208852aa28c76f9be9b03a4dd2b3c075f7a26923b4
get
Syntax (get key-name tuple)
Input type:
KeyName and Tuple | Optional(Tuple)
Output type:
AnyType
The get function fetches the value associated with a given key from the supplied typed tuple. If an Optional value is supplied as the inputted tuple, get returns an Optional type of the specified key in the tuple. If the supplied option is a (none) option, get returns (none).
Example
(get id (tuple (name "blockstack") (id 1337))) ;; Returns 1337
(get id (fetch-entry names-map (tuple (name "blockstack")))) ;; Returns (some 1337)
(get id (fetch-entry names-map (tuple (name "non-existent")))) ;; Returns (none)
hash160
Syntax (hash160 value)
Input type:
buff|int
Output type:
(buff 20)
The hash160 function computes RIPEMD160(SHA256(x)) of the inputted value. If an integer (128 bit) is supplied the hash is computed over the little-endian representation of the integer.
Example
(hash160 0) ;; Returns 0xe4352f72356db555721651aa612e00379167b30f
if
Syntax (if bool1 expr1 expr2)
Input type:
bool, A, A
Output type:
A
The if function admits a boolean argument and two expressions which must return the same type. In the case that the boolean input is true, the if function evaluates and returns expr1. If the boolean input is false, the if function evaluates and returns expr2.
Example
(if true 1 2) ;; Returns 1
(if (> 1 2) 1 2) ;; Returns 2
insert-entry!
Syntax (insert-entry! map-name key-tuple value-tuple)
Input type:
MapName, TupleA, TupleB
Output type:
bool
The insert-entry! function sets the value associated with the input key to the inputted value if and only if there is not already a value associated with the key in the map. If an insert occurs, the function returns true. If a value already existed for this key in the data map, the function returns false.
Example
(insert-entry! names-map (tuple (name "blockstack")) (tuple (id 1337))) ;; Returns 'true
(insert-entry! names-map (tuple (name "blockstack")) (tuple (id 1337))) ;; Returns 'false
(insert-entry! names-map ((name "blockstack")) ((id 1337))) ;; Same command, using a shorthand for constructing the tuple
is-none?
Syntax (is-none? value)
Input type:
Optional(A)
Output type:
bool
is-none? tests a supplied option value, returning true if the option value is (none), and false if it is a (some ...).
Example
(is-none? (get id (fetch-entry names-map (tuple (name "blockstack"))))) ;; Returns 'false
(is-none? (get id (fetch-entry names-map (tuple (name "non-existant"))))) ;; Returns 'true
is-ok?
Syntax (is-ok? value)
Input type:
Response(A,B)
Output type:
bool
is-ok? tests a supplied response value, returning true if the response was ok, and false if it was an err.
Example
(is-ok? (ok 1)) ;; Returns 'true
(is-ok? (err 1)) ;; Returns 'false
keccak256
Syntax (keccak256 value)
Input type:
buff|int
Output type:
(buff 32)
The keccak256 function computes KECCAK256(value) of the inputted value. Note that this differs from the NIST SHA-3 (that is, FIPS 202) standard. If an integer (128 bit) is supplied the hash is computed over the little-endian representation of the integer.
Example
(keccak256 0) ;; Returns 0xf490de2920c8a35fabeb13208852aa28c76f9be9b03a4dd2b3c075f7a26923b4
let
Syntax (let ((name1 expr1) (name2 expr2) ...) expr-body)
Input type:
((name2 AnyType) (name2 AnyType) ...), A
Output type:
A
The let function accepts a list of variable name and expression pairs, evaluating each expression and binding it to the corresponding variable name. The context created by this set of bindings is used for evaluating and return the value of expr-body.
Example
(let ((a 2) (b (+ 5 6 7))) (+ a b)) ;; Returns 20
list
Syntax (list expr1 expr2 expr3 ...)
Input type:
A, ...
Output type:
(list A)
The list function constructs a list composed of the inputted values. Each supplied value must be of the same type.
Example
(list (+ 1 2) 4 5) ;; Returns [3 4 5]
map
Syntax (map func list)
Input type:
Function(A) -> B, (list A)
Output type:
(list B)
The map function applies the input function func to each element of the input list, and outputs a list containing the outputs from those function applications.
Example
(map not (list true false true false)) ;; Returns 'false true false true
mod
Syntax (mod i1 i2)
Input type:
int, int
Output type:
int
Returns the integer remainder from integer dividing i1 by i2. In the event of a division by zero, throws a runtime error.
Example
(mod 2 3) ;; Returns 0
(mod 5 2) ;; Returns 1
(mod 7 1) ;; Returns 0
not
Syntax (not b1)
Input type:
bool
Output type:
bool
Returns the inverse of the boolean input.
Example
(not 'true) ;; Returns 'false
(not (eq? 1 2)) ;; Returns 'true
ok
Syntax (ok value)
Input type:
A
Output type:
Response(A,B)
The ok function constructs a response type from the input value. Use ok for creating return values in public functions. An ok value indicates that any database changes during the processing of the function should materialize.
Example
(ok 1) ;; Returns (ok 1)
or
Syntax (or b1 b2 ...)
Input type:
bool, ...
Output type:
bool
Returns true if any boolean inputs are true. Importantly, the supplied arguments are evaluated in-order and lazily. Lazy evaluation means that if one of the arguments returns false, the function short-circuits, and no subsequent arguments are evaluated.
Example
(or 'true 'false) ;; Returns 'true
(or (eq? (+ 1 2) 1) (eq? 4 4)) ;; Returns 'true
(or (eq? (+ 1 2) 1) (eq? 3 4)) ;; Returns 'false
(or (eq? (+ 1 2) 3) (eq? 4 4)) ;; Returns 'true
pow
Syntax (pow i1 i2)
Input type:
int, int
Output type:
int
Returns the result of raising i1 to the power of i2. In the event of an overflow, throws a runtime error.
Example
(pow 2 3) ;; Returns 8
(pow 2 2) ;; Returns 4
(pow 7 1) ;; Returns 7
Syntax (print expr)
Input type:
A
Output type:
A
The print function evaluates and returns its input expression. On Blockstack Core nodes configured for development (as opposed to production mining nodes), this function prints the resulting value to STDOUT (standard output).
Example
(print (+ 1 2 3)) ;; Returns 6
set-entry!
Syntax (set-entry! map-name key-tuple value-tuple)
Input type:
MapName, TupleA, TupleB
Output type:
bool
The set-entry! function sets the value associated with the input key to the inputted value. This function performs a blind update; whether or not a value is already associated with the key, the function overwrites that existing association.
Example
(set-entry! names-map (tuple (name "blockstack")) (tuple (id 1337))) ;; Returns 'true
(set-entry! names-map ((name "blockstack")) ((id 1337))) ;; Same command, using a shorthand for constructing the tuple
set-var!
Syntax (set-var! var-name expr1)
Input type:
VarName, AnyType
Output type:
bool
The set-var! function sets the value associated with the input variable to the inputted value.
Example
(set-var! cursor (+ cursor 1)) ;; Returns 'true
sha256
Syntax (sha256 value)
Input type:
buff|int
Output type:
(buff 32)
The sha256 function computes SHA256(x) of the inputted value. If an integer (128 bit) is supplied the hash is computed over the little-endian representation of the integer.
Example
(sha256 0) ;; Returns 0x374708fff7719dd5979ec875d56cd2286f6d3cf7ec317a3b25632aab28ec37bb
tuple
Syntax (tuple ((key0 expr0) (key1 expr1) ...))
Input type:
(list (KeyName AnyType))
Output type:
Tuple
The tuple function constructs a typed tuple from the supplied key and expression pairs. A get function can use typed tuples as input to select specific values from a given tuple. Key names may not appear multiple times in the same tuple definition. Supplied expressions are evaluated and associated with the expressions’ paired key name.
Example
(tuple (name "blockstack") (id 1337))
xor
Syntax (xor i1 i2)
Input type:
int, int
Output type:
int
Returns the result of bitwise exclusive or’ing i1 with i2.
Example
(xor 1 2) ;; Returns 3
(xor 120 280) ;; Returns 352 view all
This file contains the reference for the Clarity language.
Block Properties
Supported types
Int type
Bool type
Buffer type
List type
Principal type
Tuple type
Optional type
Response type
Native variables
block-height
contract-name
tx-sender
Clarity function reference
* (multiply)
+ (add)
- (subtract)
/ (divide)
< (less than)
<= (less than or equal)
> (greater than)
>= (greater than or equal)
and
as-contract
begin
contract-call!
default-to
define-data-var
define-map
define-public
define-read-only
define
delete-entry!
eq?
err
expects!
expects-err!
fetch-contract-entry
fetch-entry
fetch-var
filter
fold
get-block-info
get
hash160
if
insert-entry!
is-none?
is-ok?
keccak256
let
list
map
mod
not
ok
or
pow
set-entry!
set-var!
sha256
tuple
xor
Block Properties
The get-block-info function fetches property details for a block at a specified block height. For example:
(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:
Property
Definition
header-hash
A 32-byte buffer containing the block hash.
burnchain-header-hash
A 32-byte buffer that contains the hash from the proof of burn.
vrf-seed
A 32-byte buffer containing the Verifiable Random Function (VRF) seed value used for the block.
time
An integer value containing that roughly corresponds to when the block was mined. This is a Unix epoch timestamp in seconds.
Warning: The time does not increase monotonically with each block. Block times are accurate only to within two hours. See BIP113 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.
Int type
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.
Bool type
Supports values of 'true or 'false.
Buffer type
Buffer types represent fixed-length byte buffers. Currently, the only way to construct a Buffer is using string literals, for example "alice.id" or hash160("bob.id")
All of the hash functions return buffers:
hash160 sha256 keccak256
The block properties header-hash, burnchain-header-hash, and vrf-seed are all buffers.
List type
Clarity supports 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.
Principal type
Clarity provides this primitive for checking whether or not the smart contract transaction was signed by a particular principal. Principals represent a spending entity and are roughly equivalent to a Stacks address. The principal’s signature is not checked by the smart contract, but by the virtual machine. A smart contract function can use the globally defined tx-sender variable to obtain the current principal.
Smart contracts may also be principals (represented by the smart contract’s identifier). However, there is no private key associated with the smart contract, and it cannot broadcast a signed transaction on the blockchain. A smart contract uses the special variable contract-name to refer to its own principal.
Tuple type
To support the use of named fields in keys and values, Clarity allows the construction of named tuples using a function (tuple ...), for example
(define imaginary-number-a (tuple (real 1) (i 2)))
(define imaginary-number-b (tuple (real 2) (i 3)))
This allows for creating named tuples on the fly, which is useful for data maps where the keys and values are themselves named tuples. Values in a given mapping are set or fetched using:
Function
Description
(fetch-entry map-name key-tuple)
Fetches the value associated with a given key in the map, or returns none if there is no such value.
(set-entry! map-name key-tuple value-tuple)
Sets the value of key-tuple in the data map
(insert-entry! map-name key-tuple value-tuple)
Sets the value of key-tuple in the data map if and only if an entry does not already exist.
(delete-entry! map-name key-tuple)
Deletes key-tuple from the data map.
To access a named value of a given tuple, the (get name tuple) function returns that item from the tuple.
Optional type
Represents an optional value. This is used in place of the typical usage of “null” values in other languages, and represents a type that can either be some value or none. Optional types are used as the return types of data-map functions.
Response type
Response types represent the result of a public function. Use this type to indicate and return data associated with the execution of the function. Also, the response should indicate whether the function error’ed (and therefore did not materialize any data in the database) or ran ok (in which case data materialized in the database).
Response types contain two subtypes – a response type in the event of ok (that is, a public function returns an integer code on success) and an err type (that is, a function returns a buffer on error).
Native variables
The Clarity language includes native variables you can use in your contract.
block-height
The height of a block in the Stacks blockchain. Block height is the number of blocks in the chain between any given block and the very first block in the blockchain. You can obtain a block-height via the get-block-info function.
contract-name
Represents the current contract.
tx-sender
Represents the current principal. This variable does not change during inter-contract calls. This 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. This enables a wide variety of applications, but it comes with some dangers for users of smart contracts. Static analysis of Clarity contracts guarantees the language allows clients to deduce which functions a given smart contract will ever call. Good clients should always warn users about any potential side effects of a given transaction.
Clarity function reference
* (multiply)
Syntax (* i1 i2...)
Input type:
int, ...
Output type:
int
Multiplies a variable number of integer inputs and returns the result. In the event of an overflow, throws a runtime error.
Example
(* 2 3) ;; Returns 6
(* 5 2) ;; Returns 10
(* 2 2 2) ;; Returns 8
+ (add)
Syntax (+ i1 i2...)
Input type:
int, ...
Output type:
int
Adds a variable number of integer inputs and returns the result. In the event of an overflow, throws a runtime error.
Example
(+ 1 2 3) ;; Returns 6
- (subtract)
Syntax (- i1 i2...)
Input type:
int, ...
Output type:
int
Subtracts a variable number of integer inputs and returns the result. In the event of an underflow, throws a runtime error.
Example
(- 2 1 1) ;; Returns 0
(- 0 3) ;; Returns -3
/ (divide)
Syntax (/ i1 i2...)
Input type:
int, ...
Output type:
int
Integer divides a variable number of integer inputs and returns the result. In the event of division by zero, throws a runtime error.
Example
(/ 2 3) ;; Returns 0
(/ 5 2) ;; Returns 2
(/ 4 2 2) ;; Returns 1
< (less than)
Syntax (< i1 i2)
Input type:
int, int
Output type:
bool
Compares two integers, returning true if i1 is less than i2 and false otherwise.
Example
(< 1 2) ;; Returns 'true
(< 5 2) ;; Returns 'false
<= (less than or equal)
Syntax (> i1 i2)
Input type:
int, int
Output type:
bool
Compares two integers, returning true if i1 is less than or equal to i2 and false otherwise.
Example
(<= 1 1) ;; Returns 'true
(<= 5 2) ;; Returns 'false
> (greater than)
Syntax (> i1 i2)
Input type:
int, int
Output type:
bool
Compares two integers, returning true if i1 is greater than i2 and false otherwise.
Example
(> 1 2) ;; Returns 'false
(> 5 2) ;; Returns 'true
>= (greater than or equal)
Syntax (>= i1 i2)
Input type:
int, int
Output type:
bool
Compares two integers, returning true if i1 is greater than or equal to i2 and false otherwise.
Example
(>= 1 1) ;; Returns 'true
(>= 5 2) ;; Returns 'true
and
Syntax (and b1 b2 ...)
Input type:
bool, ...
Output type:
bool
Returns true if all boolean inputs are true. Importantly, the supplied arguments are evaluated in-order and lazily. Lazy evaluation means that if one of the arguments returns false, the function short-circuits, and no subsequent arguments are evaluated.
Example
(and 'true 'false) ;; Returns 'false
(and (eq? (+ 1 2) 1) (eq? 4 4)) ;; Returns 'false
(and (eq? (+ 1 2) 3) (eq? 4 4)) ;; Returns 'true
as-contract
Syntax (as-contract expr)
Input type:
A
Output type:
A
The as-contract function switches the current context’s tx-sender value to the contract’s principal and executes expr with that context. It returns the resulting value of expr.
Example
(as-contract (print tx-sender)) ;; Returns 'CTcontract.name
begin
Syntax (begin expr1 expr2 expr3 ... expr-last)
Input type:
AnyType, ... A
Output type:
A
The begin function evaluates each of its input expressions, returning the return value of the last such expression.
Example
(begin (+ 1 2) 4 5) ;; Returns 5
contract-call!
Syntax (contract-call! contract-name function-name arg0 arg1 ...)
Input type:
ContractName, PublicFunctionName, Arg0, ...
Output type:
Response(A,B)
The contract-call! function executes the given public function of the given contract. You may not this function to call a public function defined in the current contract. If the public function returns err, any database changes resulting from calling contract-call! are aborted. If the function returns ok, database changes occurred.
Example
(contract-call! tokens transfer 'SZ2J6ZY48GV1EZ5V2V5RB9MP66SW86PYKKQ9H6DPR 19) ;; Returns (ok 1)
default-to
Syntax (default-to default-value option-value)
Input type:
A, Optional(A)
Output type:
A
The default-to function attempts to ‘unpack’ the second argument: if the argument is a (some ...) option, it returns the inner value of the option. If the second argument is a (none) value, default-to it returns the value of default-value.
Example
(default-to 0 (get id (fetch-entry names-map (tuple (name "blockstack"))))) ;; Returns 1337
(default-to 0 (get id (fetch-entry names-map (tuple (name "non-existant"))))) ;; Returns 0
define-data-var
Syntax (define-data-var var-name type value)
Input type:
VarName, TypeDefinition, Value
Output type:
Not Applicable
define-data-var is used to define a new persisted variable for use in a smart contract. Such variable are only modifiable by the current smart contract.
Persisted variable are defined with a type and a value.
Like other kinds of definition statements, define-data-var may only be used at the top level of a smart contract definition (i.e., you cannot put a define statement in the middle of a function body).
Example
(define-data-var size int 0)
(define (set-size (value int))
(set-var! size value))
(set-size 1)
(set-size 2)
define-map
Syntax (define-map map-name ((key-name-0 key-type-0) ...) ((val-name-0 val-type-0) ...))
Input type:
MapName, KeyTupleDefinition, MapTupleDefinition
Output type:
Not Applicable
define-map is used to define a new datamap for use in a smart contract. Such maps are only modifiable by the current smart contract.
Maps are defined with a key tuple type and value tuple type. These are defined using a list of name and type pairs, e.g., a key type might be ((id int)), which is a tuple with a single “id” field of type int.
Like other kinds of definition statements, define-map may only be used at the top level of a smart contract definition (i.e., you cannot put a define statement in the middle of a function body).
Example
(define-map squares ((x int)) ((square int)))
(define (add-entry (x int))
(insert-entry! squares ((x 2)) ((square (* x x)))))
(add-entry 1)
(add-entry 2)
(add-entry 3)
(add-entry 4)
(add-entry 5)
define-public
Syntax (define-public (function-name (arg-name-0 arg-type-0) (arg-name-1 arg-type-1) ...) function-body)
Input type:
MethodSignature, MethodBody
Output type:
Not Applicable
define-public is used to define a public function and transaction for a smart contract. Public functions are callable from other smart contracts and may be invoked directly by users by submitting a transaction to the Stacks blockchain.
Like other kinds of definition statements, define-public may only be used at the top level of a smart contract definition (i.e., you cannot put a define statement in the middle of a function body).
Public functions must return a ResponseType (using either ok or err). Any datamap modifications performed by a public function is aborted if the function returns an err type. Public functions may be invoked by other contracts via contract-call!.
Example
(define-public (hello-world (input int))
(begin (print (+ 2 input))
(ok input)))
define-read-only
Syntax (define-read-only (function-name (arg-name-0 arg-type-0) (arg-name-1 arg-type-1) ...) function-body)
Input type:
MethodSignature, MethodBody
Output type:
Not Applicable
define-read-only is used to define a public read-only function for a smart contract. Such functions are callable from other smart contracts.
Like other kinds of definition statements, define-read-only may only be used at the top level of a smart contract definition (i.e., you cannot put a define statement in the middle of a function body).
Read-only functions may return any type. However, read-only functions may not perform any datamap modifications, or call any functions which perform such modifications. This is enforced both during type checks and during the execution of the function. Public read-only functions may be invoked by other contracts via contract-call!.
Example
(define-read-only (just-return-one-hundred)
(* 10 10))
define
Syntax (define (function-name (arg-name-0 arg-type-0) (arg-name-1 arg-type-1) ...) function-body)
Input type:
MethodSignature, MethodBody
Output type:
Not Applicable
define is used to define private functions for a smart contract. Private functions may not be called from other smart contracts, nor may they be invoked directly by users. Instead, these functions may only be invoked by other functions defined in the same smart contract.
Like other kinds of definition statements, define may only be used at the top level of a smart contract definition (i.e., you cannot put a define statement in the middle of a function body).
Private functions may return any type.
Example
(define (max-of (i1 int) (i2 int))
(if (> i1 i2)
i1
i2))
(max-of 4 6) ;; returns 6
delete-entry!
Syntax (delete-entry! map-name key-tuple)
Input type:
MapName, Tuple
Output type:
bool
The delete-entry! function removes the value associated with the input key for the given map. If an item exists and is removed, the function returns true. If a value did not exist for this key in the data map, the function returns false.
Example
(delete-entry! names-map (tuple (name "blockstack"))) ;; Returns 'true
(delete-entry! names-map (tuple (name "blockstack"))) ;; Returns 'false
(delete-entry! names-map ((name "blockstack"))) ;; Same command, using a shorthand for constructing the tuple
eq?
Syntax (eq? v1 v2...)
Input type:
A, A, ...
Output type:
bool
Compares the inputted values, returning true if they are all equal. Note that unlike the (and ...) function, (eq? ...) will not short-circuit.
Example
(eq? 1 1) ;; Returns 'true
(eq? 1 'false) ;; Returns 'false
(eq? "abc" 234 234) ;; Returns 'false
err
Syntax (err value)
Input type:
A
Output type:
Response(A,B)
The err function constructs a response type from the input value. Use err for creating return values in public functions. An err value indicates that any database changes during the processing of the function should be rolled back.
Example
(err 'true) ;; Returns (err 'true)
expects!
Syntax (expects! option-input thrown-value)
Input type:
Optional(A) | Response(A,B), C
Output type:
A
The expects! function attempts to ‘unpack’ the first argument: if the argument is an option type, and the argument is a (some ...) option, expects! returns the inner value of the option. If the argument is a response type, and the argument is an (ok ...) response, expects! returns the inner value of the ok. If the supplied argument is either an (err ...) or a (none) value, expects! returns thrown-value from the current function and exits the current control-flow.
Example
(expects! (fetch-entry names-map (tuple (name "blockstack"))) (err 1)) ;; Returns (tuple (id 1337))
expects-err!
Syntax (expects-err! response-input thrown-value)
Input type:
Response(A,B), C
Output type:
B
The expects-err! function attempts to ‘unpack’ the first argument: if the argument is an (err ...) response, expects-err! returns the inner value of the err. If the supplied argument is an (ok ...) value, expects-err! returns thrown-value from the current function and exits the current control-flow.
Example
(expects-err! (err 1) 'false) ;; Returns 1
fetch-contract-entry
Syntax (fetch-contract-entry contract-name map-name key-tuple)
Input type:
ContractName, MapName, Tuple
Output type:
Optional(Tuple)
The fetch-contract-entry function looks up and returns an entry from a contract other than the current contract’s data map. The value is looked up using key-tuple. If there is no value associated with that key in the data map, the function returns a (none) option. Otherwise, it returns (some value).
Example
(expects! (fetch-contract-entry names-contract names-map (tuple (name "blockstack")) (err 1))) ;; Returns (tuple (id 1337))
(expects! (fetch-contract-entry names-contract names-map ((name "blockstack")) (err 1)));; Same command, using a shorthand for constructing the tuple
fetch-entry
Syntax (fetch-entry map-name key-tuple)
Input type:
MapName, Tuple
Output type:
Optional(Tuple)
The fetch-entry function looks up and returns an entry from a contract’s data map. The value is looked up using key-tuple. If there is no value associated with that key in the data map, the function returns a (none) option. Otherwise, it returns (some value)
Example
(expects! (fetch-entry names-map (tuple (name "blockstack"))) (err 1)) ;; Returns (tuple (id 1337))
(expects! (fetch-entry names-map ((name "blockstack"))) (err 1)) ;; Same command, using a shorthand for constructing the tuple
fetch-var
Syntax (fetch-var var-name)
Input type:
VarName
Output type:
A
The fetch-var function looks up and returns an entry from a contract’s data map. The value is looked up using var-name.
Example
(fetch-var cursor) ;; Returns cursor
filter
Syntax (filter func list)
Input type:
Function(A) -> bool, (list A)
Output type:
(list A)
The filter function applies the input function func to each element of the input list, and returns the same list with any elements removed for which the func returned false.
Example
(filter not (list true false true false)) ;; Returns (list false false)
fold
Syntax (fold func list initial-value)
Input type:
Function(A, B) -> B, (list A)
Output type:
B
The fold function applies the input function func to each element of the input list and the output of the previous application of the fold function. When invoked on the first list element, it uses the initial-value as the second input. fold returns the last value return by the successive applications.
Example
(fold * (list 2 2 2) 1) ;; Returns 8
(fold * (list 2 2 2) 0) ;; Returns 0
get-block-info
Syntax (get-block-info prop-name block-height-expr)
Input type:
BlockInfoPropertyName, BlockHeightInt
Output type:
buff | int
The get-block-info function fetches data for a block of the given block height. The value and type returned are determined by the specified BlockInfoPropertyName. If the provided BlockHeightInt does not correspond to an existing block, the function is aborted. The currently available property names are time, header-hash, burnchain-header-hash, and vrf-seed.
The time property returns an integer value of the block header time field. This is a Unix epoch timestamp in seconds which roughly corresponds to when the block was mined. Warning: this does not increase monotonically with each block and block times are accurate only to within two hours. See BIP113 for more information.
The header-hash, burnchain-header-hash, and vrf-seed properties return a 32-byte buffer.
Example
(get-block-info time 10) ;; Returns 1557860301
(get-block-info header-hash 2) ;; Returns 0x374708fff7719dd5979ec875d56cd2286f6d3cf7ec317a3b25632aab28ec37bb
(get-block-info vrf-seed 6) ;; Returns 0xf490de2920c8a35fabeb13208852aa28c76f9be9b03a4dd2b3c075f7a26923b4
get
Syntax (get key-name tuple)
Input type:
KeyName and Tuple | Optional(Tuple)
Output type:
AnyType
The get function fetches the value associated with a given key from the supplied typed tuple. If an Optional value is supplied as the inputted tuple, get returns an Optional type of the specified key in the tuple. If the supplied option is a (none) option, get returns (none).
Example
(get id (tuple (name "blockstack") (id 1337))) ;; Returns 1337
(get id (fetch-entry names-map (tuple (name "blockstack")))) ;; Returns (some 1337)
(get id (fetch-entry names-map (tuple (name "non-existent")))) ;; Returns (none)
hash160
Syntax (hash160 value)
Input type:
buff|int
Output type:
(buff 20)
The hash160 function computes RIPEMD160(SHA256(x)) of the inputted value. If an integer (128 bit) is supplied the hash is computed over the little-endian representation of the integer.
Example
(hash160 0) ;; Returns 0xe4352f72356db555721651aa612e00379167b30f
if
Syntax (if bool1 expr1 expr2)
Input type:
bool, A, A
Output type:
A
The if function admits a boolean argument and two expressions which must return the same type. In the case that the boolean input is true, the if function evaluates and returns expr1. If the boolean input is false, the if function evaluates and returns expr2.
Example
(if true 1 2) ;; Returns 1
(if (> 1 2) 1 2) ;; Returns 2
insert-entry!
Syntax (insert-entry! map-name key-tuple value-tuple)
Input type:
MapName, TupleA, TupleB
Output type:
bool
The insert-entry! function sets the value associated with the input key to the inputted value if and only if there is not already a value associated with the key in the map. If an insert occurs, the function returns true. If a value already existed for this key in the data map, the function returns false.
Example
(insert-entry! names-map (tuple (name "blockstack")) (tuple (id 1337))) ;; Returns 'true
(insert-entry! names-map (tuple (name "blockstack")) (tuple (id 1337))) ;; Returns 'false
(insert-entry! names-map ((name "blockstack")) ((id 1337))) ;; Same command, using a shorthand for constructing the tuple
is-none?
Syntax (is-none? value)
Input type:
Optional(A)
Output type:
bool
is-none? tests a supplied option value, returning true if the option value is (none), and false if it is a (some ...).
Example
(is-none? (get id (fetch-entry names-map (tuple (name "blockstack"))))) ;; Returns 'false
(is-none? (get id (fetch-entry names-map (tuple (name "non-existant"))))) ;; Returns 'true
is-ok?
Syntax (is-ok? value)
Input type:
Response(A,B)
Output type:
bool
is-ok? tests a supplied response value, returning true if the response was ok, and false if it was an err.
Example
(is-ok? (ok 1)) ;; Returns 'true
(is-ok? (err 1)) ;; Returns 'false
keccak256
Syntax (keccak256 value)
Input type:
buff|int
Output type:
(buff 32)
The keccak256 function computes KECCAK256(value) of the inputted value. Note that this differs from the NIST SHA-3 (that is, FIPS 202) standard. If an integer (128 bit) is supplied the hash is computed over the little-endian representation of the integer.
Example
(keccak256 0) ;; Returns 0xf490de2920c8a35fabeb13208852aa28c76f9be9b03a4dd2b3c075f7a26923b4
let
Syntax (let ((name1 expr1) (name2 expr2) ...) expr-body)
Input type:
((name2 AnyType) (name2 AnyType) ...), A
Output type:
A
The let function accepts a list of variable name and expression pairs, evaluating each expression and binding it to the corresponding variable name. The context created by this set of bindings is used for evaluating and return the value of expr-body.
Example
(let ((a 2) (b (+ 5 6 7))) (+ a b)) ;; Returns 20
list
Syntax (list expr1 expr2 expr3 ...)
Input type:
A, ...
Output type:
(list A)
The list function constructs a list composed of the inputted values. Each supplied value must be of the same type.
Example
(list (+ 1 2) 4 5) ;; Returns [3 4 5]
map
Syntax (map func list)
Input type:
Function(A) -> B, (list A)
Output type:
(list B)
The map function applies the input function func to each element of the input list, and outputs a list containing the outputs from those function applications.
Example
(map not (list true false true false)) ;; Returns 'false true false true
mod
Syntax (mod i1 i2)
Input type:
int, int
Output type:
int
Returns the integer remainder from integer dividing i1 by i2. In the event of a division by zero, throws a runtime error.
Example
(mod 2 3) ;; Returns 0
(mod 5 2) ;; Returns 1
(mod 7 1) ;; Returns 0
not
Syntax (not b1)
Input type:
bool
Output type:
bool
Returns the inverse of the boolean input.
Example
(not 'true) ;; Returns 'false
(not (eq? 1 2)) ;; Returns 'true
ok
Syntax (ok value)
Input type:
A
Output type:
Response(A,B)
The ok function constructs a response type from the input value. Use ok for creating return values in public functions. An ok value indicates that any database changes during the processing of the function should materialize.
Example
(ok 1) ;; Returns (ok 1)
or
Syntax (or b1 b2 ...)
Input type:
bool, ...
Output type:
bool
Returns true if any boolean inputs are true. Importantly, the supplied arguments are evaluated in-order and lazily. Lazy evaluation means that if one of the arguments returns false, the function short-circuits, and no subsequent arguments are evaluated.
Example
(or 'true 'false) ;; Returns 'true
(or (eq? (+ 1 2) 1) (eq? 4 4)) ;; Returns 'true
(or (eq? (+ 1 2) 1) (eq? 3 4)) ;; Returns 'false
(or (eq? (+ 1 2) 3) (eq? 4 4)) ;; Returns 'true
pow
Syntax (pow i1 i2)
Input type:
int, int
Output type:
int
Returns the result of raising i1 to the power of i2. In the event of an overflow, throws a runtime error.
Example
(pow 2 3) ;; Returns 8
(pow 2 2) ;; Returns 4
(pow 7 1) ;; Returns 7
Syntax (print expr)
Input type:
A
Output type:
A
The print function evaluates and returns its input expression. On Blockstack Core nodes configured for development (as opposed to production mining nodes), this function prints the resulting value to STDOUT (standard output).
Example
(print (+ 1 2 3)) ;; Returns 6
set-entry!
Syntax (set-entry! map-name key-tuple value-tuple)
Input type:
MapName, TupleA, TupleB
Output type:
bool
The set-entry! function sets the value associated with the input key to the inputted value. This function performs a blind update; whether or not a value is already associated with the key, the function overwrites that existing association.
Example
(set-entry! names-map (tuple (name "blockstack")) (tuple (id 1337))) ;; Returns 'true
(set-entry! names-map ((name "blockstack")) ((id 1337))) ;; Same command, using a shorthand for constructing the tuple
set-var!
Syntax (set-var! var-name expr1)
Input type:
VarName, AnyType
Output type:
bool
The set-var! function sets the value associated with the input variable to the inputted value.
Example
(set-var! cursor (+ cursor 1)) ;; Returns 'true
sha256
Syntax (sha256 value)
Input type:
buff|int
Output type:
(buff 32)
The sha256 function computes SHA256(x) of the inputted value. If an integer (128 bit) is supplied the hash is computed over the little-endian representation of the integer.
Example
(sha256 0) ;; Returns 0x374708fff7719dd5979ec875d56cd2286f6d3cf7ec317a3b25632aab28ec37bb
tuple
Syntax (tuple ((key0 expr0) (key1 expr1) ...))
Input type:
(list (KeyName AnyType))
Output type:
Tuple
The tuple function constructs a typed tuple from the supplied key and expression pairs. A get function can use typed tuples as input to select specific values from a given tuple. Key names may not appear multiple times in the same tuple definition. Supplied expressions are evaluated and associated with the expressions’ paired key name.
Example
(tuple (name "blockstack") (id 1337))
xor
Syntax (xor i1 i2)
Input type:
int, int
Output type:
int
Returns the result of bitwise exclusive or’ing i1 with i2.
Example
(xor 1 2) ;; Returns 3
(xor 120 280) ;; Returns 352
Quickstart for the SDK
Others • blockstack app store posted the article • 0 comments • 1556 views • 2019-06-28 01:40
About this tutorial and the prerequisites you need
Task 1: Generate an initial Clarity project
Task 2: Investigate the generated project
Task 3: Try to expand the contract
About this tutorial and the prerequisites you need
Note: 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.
For this tutorial, you will use npm to manage dependencies and scripts. The tutorial relies on the npm dependency manager. Before you begin, verify you have installed npm using the which command to verify.
$ which npm
/usr/local/bin/npm
If you don’t find npm in your system, install it.
You use npm to install Yeoman. Yeoman is a generic scaffolding system that helps users rapidly start new projects and streamline the maintenance of existing projects. Verify you have installed yo using the which command.
$ which yo
/usr/local/bin/yo
If you don’t have Yeoman, you can install it with the npm install -g yo command.
Task 1: Generate an initial Clarity project
The SDK uses Yeoman to generate a project scaffold — an initial set of directories and files.
1. Create a new directory for your project.
mkdir hello-clarity-sdk2. Change into your new project directory.cd hello-clarity-sdk3. Use the npm command to initialize a Clarity project.
npm init yo clarity-dev npx: installed 15 in 1.892s create package.json create .vscode/extensions.json ... Project created at /private/tmp/hello-clarity-sdk ✔ create-yo ok!Depending on your connection speed, it may take time to construct the scaffolding.
Task 2: Investigate the generated project
Your project should contain three directories:
The contracts directory contains a single file in sample/hello-world.clar file.
(define (hello-world)
"hello world")
(define (echo-number (val int))
val)
The contract exposes 2 rudimentary functions. The say-hi returns a hello world string. The increment-number: echos val.
The project also includes tests/hello-world.ts file. The test is written in Typescript. You can also write tests in Javascript.
import { Client, Provider, ProviderRegistry, Result } from "@blockstack/clarity";
import { assert } from "chai";
describe("hello world contract test suite", () => {
let helloWorldClient: Client;
let provider: Provider;
before(async () => {
provider = await ProviderRegistry.createProvider();
helloWorldClient = new Client("hello-world", "sample/hello-world", provider);
});
it("should have a valid syntax", async () => {
await helloWorldClient.checkContract();
});
describe("deploying an instance of the contract", () => {
before(async () => {
await helloWorldClient.deployContract();
});
it("should print hello world message", async () => {
const query = helloWorldClient.createQuery({ method: { name: "hello-world", args: } });
const receipt = await helloWorldClient.submitQuery(query);
const result = Result.unwrap(receipt);
const parsedResult = Buffer.from(result.replace("0x", ""), "hex").toString();
assert.equal(parsedResult, "hello world");
});
it("should echo number", async () => {
const query = helloWorldClient.createQuery({
method: { name: "echo-number", args: ["123"] }
});
const receipt = await helloWorldClient.submitQuery(query);
const result = Result.unwrap(receipt);
assert.equal(result, "123");
});
});
after(async () => {
await provider.close();
});
});
The hello-world.ts test file is a client that runs the hello-world.clar contract. Tests are critical for smart contracts as they are intended to manipulate assets and their ownership. These manipulations are irreversible within a blockchain. As you create a contracts, you should not be surprise if you end up spending more time and having more code in your tests than in your contracts directory. The tests/hello-world.ts file in the scaffold has the following content:
The first part of the test (lines 1 -10) sets up the test environment. It defines a Clarity provider and launches it (line 9). The Client instance contains a contract name and the path to the sample code. This test also checks the client (line 14) and then launches it (line 19), this is equivalent to running clarity-cli check with the command line. The remaining test code exercises the contract. Try running this test.
npm run test
> [email protected] test /private/tmp/hello-clarity-sdk
> mocha
hello world contract test suite
✓ should have a valid syntax
deploying an instance of the contract
✓ should print hello world message
✓ should echo number
3 passing (182ms)
In the next section, try your hand at expanding the hello-world.clar program.
Task 3: Try to expand the contract
In this task, you are challenged to expand the contents of the contracts/hello-world.clar file. Use your favorite editor and open the contracts/hello-world.clar file. If you use Visual Studio Code, you can install the Blockstack Clarity extension. The extension provides syntax coloration and some autocompletion.
Edit the hello-world.clar file.
;; Functions
(define (hello-world)
"hello world")
(define (echo-number (val int))
val)
Use the + function to create a increment-number-by-10 function.
answer:
;; Functions
(define (say-hi)
"hello world")
(define (increment-number (number int))
(+ 1 number))
(define (increment-number-by-10 (number int))
(+ 10 number))
Use the + and - function to create a decrement-number user-defined method.
answer: ;; Functions
(define (say-hi)
"hello world")
(define (increment-number (number int))
(+ 1 number))
(define (increment-number-by-10 (number int))
(+ 10 number))
(define (decrement-number (number int))
(- number 1))
Finally, try adding a counter variable and be sure to store it. Increment counter in your code and add a get-counter funtion to return the result. Here is a hint, you can add a var` to a contract by adding the following line (before the function):
```cl ;; Storage (define-data-var internal-value int 0)
answer:
;; Storage
(define-data-var counter int 0)
;; Functions
(define (say-hi)
"hello world")
(define (increment-number (number int))
(+ 1 number))
(define (increment-number-by-10 (number int))
(+ 10 number))
(define (decrement-number (number int))
(- number 1))
(define (increment-counter)
(set-var! counter (+ 1 counter)))
(define (get-counter)
(counter))
To review other, longer sample programs visit the ]clarity-js-sdk[/url] repository.
view all
About this tutorial and the prerequisites you need
Task 1: Generate an initial Clarity project
Task 2: Investigate the generated project
Task 3: Try to expand the contract
About this tutorial and the prerequisites you need
Note: 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.
For this tutorial, you will use npm to manage dependencies and scripts. The tutorial relies on the npm dependency manager. Before you begin, verify you have installed npm using the which command to verify.
$ which npm
/usr/local/bin/npm
If you don’t find npm in your system, install it.
You use npm to install Yeoman. Yeoman is a generic scaffolding system that helps users rapidly start new projects and streamline the maintenance of existing projects. Verify you have installed yo using the which command.
$ which yo
/usr/local/bin/yo
If you don’t have Yeoman, you can install it with the npm install -g yo command.
Task 1: Generate an initial Clarity project
The SDK uses Yeoman to generate a project scaffold — an initial set of directories and files.
1. Create a new directory for your project.
mkdir hello-clarity-sdk2. Change into your new project directory.
cd hello-clarity-sdk3. Use the npm command to initialize a Clarity project.
npm init yo clarity-dev npx: installed 15 in 1.892s create package.json create .vscode/extensions.json ... Project created at /private/tmp/hello-clarity-sdk ✔ create-yo ok!Depending on your connection speed, it may take time to construct the scaffolding.
Task 2: Investigate the generated project
Your project should contain three directories:

The contracts directory contains a single file in sample/hello-world.clar file.
(define (hello-world)
"hello world")
(define (echo-number (val int))
val)
The contract exposes 2 rudimentary functions. The say-hi returns a hello world string. The increment-number: echos val.
The project also includes tests/hello-world.ts file. The test is written in Typescript. You can also write tests in Javascript.
import { Client, Provider, ProviderRegistry, Result } from "@blockstack/clarity";
import { assert } from "chai";
describe("hello world contract test suite", () => {
let helloWorldClient: Client;
let provider: Provider;
before(async () => {
provider = await ProviderRegistry.createProvider();
helloWorldClient = new Client("hello-world", "sample/hello-world", provider);
});
it("should have a valid syntax", async () => {
await helloWorldClient.checkContract();
});
describe("deploying an instance of the contract", () => {
before(async () => {
await helloWorldClient.deployContract();
});
it("should print hello world message", async () => {
const query = helloWorldClient.createQuery({ method: { name: "hello-world", args: } });
const receipt = await helloWorldClient.submitQuery(query);
const result = Result.unwrap(receipt);
const parsedResult = Buffer.from(result.replace("0x", ""), "hex").toString();
assert.equal(parsedResult, "hello world");
});
it("should echo number", async () => {
const query = helloWorldClient.createQuery({
method: { name: "echo-number", args: ["123"] }
});
const receipt = await helloWorldClient.submitQuery(query);
const result = Result.unwrap(receipt);
assert.equal(result, "123");
});
});
after(async () => {
await provider.close();
});
});The hello-world.ts test file is a client that runs the hello-world.clar contract. Tests are critical for smart contracts as they are intended to manipulate assets and their ownership. These manipulations are irreversible within a blockchain. As you create a contracts, you should not be surprise if you end up spending more time and having more code in your tests than in your contracts directory. The tests/hello-world.ts file in the scaffold has the following content:
The first part of the test (lines 1 -10) sets up the test environment. It defines a Clarity provider and launches it (line 9). The Client instance contains a contract name and the path to the sample code. This test also checks the client (line 14) and then launches it (line 19), this is equivalent to running clarity-cli check with the command line. The remaining test code exercises the contract. Try running this test.
npm run test
> [email protected] test /private/tmp/hello-clarity-sdk
> mocha
hello world contract test suite
✓ should have a valid syntax
deploying an instance of the contract
✓ should print hello world message
✓ should echo number
3 passing (182ms)
In the next section, try your hand at expanding the hello-world.clar program.
Task 3: Try to expand the contract
In this task, you are challenged to expand the contents of the contracts/hello-world.clar file. Use your favorite editor and open the contracts/hello-world.clar file. If you use Visual Studio Code, you can install the Blockstack Clarity extension. The extension provides syntax coloration and some autocompletion.
Edit the hello-world.clar file.
;; Functions
(define (hello-world)
"hello world")
(define (echo-number (val int))
val)
Use the + function to create a increment-number-by-10 function.
answer:
;; Functions
(define (say-hi)
"hello world")
(define (increment-number (number int))
(+ 1 number))
(define (increment-number-by-10 (number int))
(+ 10 number))
Use the + and - function to create a decrement-number user-defined method.
answer:
;; FunctionsFinally, try adding a counter variable and be sure to store it. Increment counter in your code and add a get-counter funtion to return the result. Here is a hint, you can add a var` to a contract by adding the following line (before the function):
(define (say-hi)
"hello world")
(define (increment-number (number int))
(+ 1 number))
(define (increment-number-by-10 (number int))
(+ 10 number))
(define (decrement-number (number int))
(- number 1))
```cl ;; Storage (define-data-var internal-value int 0)
answer:
;; Storage
(define-data-var counter int 0)
;; Functions
(define (say-hi)
"hello world")
(define (increment-number (number int))
(+ 1 number))
(define (increment-number-by-10 (number int))
(+ 10 number))
(define (decrement-number (number int))
(- number 1))
(define (increment-counter)
(set-var! counter (+ 1 counter)))
(define (get-counter)
(counter))
To review other, longer sample programs visit the ]clarity-js-sdk[/url] repository.
clarity smart contract language - cli command line
Others • blockstack app store posted the article • 0 comments • 1385 views • 2019-06-28 01:27
You use the clarity-cli command to work with smart contracts within the Blockstack virtual environment. This command has the following subcommands:
initialize
mine_block
get_block_height
check
launch
eval
eval_raw
repl
execute
generate_address
initialize
clarity-cli initialize [vm-state.db]Initializes a local VM state database. If the database exists, this command throws an error.
mine_block
clarity-cli mine_block [block time] [vm-state.db]Simulates mining a new block.
get_block_height
clarity-cli get_block_height [vm-state.db]
Prints the simulated block height.
check
clarity-cli check [program-file.scm] (vm-state.db)
Type checks a potential contract definition.
launch
clarity-cli launch [contract-name] [contract-definition.scm] [vm-state.db]Launches a new contract in the local VM state database.
eval
clarity-cli eval [context-contract-name] (program.scm) [vm-state.db]Evaluates, in read-only mode, a program in a given contract context.
eval_raw
Type check and evaluate an expression for validity inside of a function’s source. It does not evaluate within a contract or database context.
repl
clarity-cli repl
Type check and evaluate expressions in a stdin/stdout loop.
execute
clarity-cli execute [vm-state.db] [contract-name] [public-function-name] [sender-address] [args...]
Executes a public function of a defined contract.
generate_address
clarity-cli generate_addressGenerates a random Stacks public address for testing purposes.
view all
You use the clarity-cli command to work with smart contracts within the Blockstack virtual environment. This command has the following subcommands:
initialize
mine_block
get_block_height
check
launch
eval
eval_raw
repl
execute
generate_address
initialize
clarity-cli initialize [vm-state.db]Initializes a local VM state database. If the database exists, this command throws an error.mine_block
clarity-cli mine_block [block time] [vm-state.db]Simulates mining a new block.
get_block_height
clarity-cli get_block_height [vm-state.db]Prints the simulated block height.
check
clarity-cli check [program-file.scm] (vm-state.db)Type checks a potential contract definition.
launch
clarity-cli launch [contract-name] [contract-definition.scm] [vm-state.db]Launches a new contract in the local VM state database.
eval
clarity-cli eval [context-contract-name] (program.scm) [vm-state.db]Evaluates, in read-only mode, a program in a given contract context.
eval_raw
Type check and evaluate an expression for validity inside of a function’s source. It does not evaluate within a contract or database context.
repl
clarity-cli replType check and evaluate expressions in a stdin/stdout loop.
execute
clarity-cli execute [vm-state.db] [contract-name] [public-function-name] [sender-address] [args...]
Executes a public function of a defined contract.
generate_address
clarity-cli generate_addressGenerates a random Stacks public address for testing purposes.
Hello Clarity tutorial
Others • blockstack app store posted the article • 0 comments • 1530 views • 2019-06-28 01:16
Before you begin (pre-requisites)
Task 1: Set up the test environment
Task 2: Review a simple Clarity program
Task 3: Initialize data-space and launch contracts
Task 4. Examine the SQLite database
Task 5: Execute a public function
Task 6: Spend tokens by registering a name
Before you begin (pre-requisites)
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 Docker installed on your workstation.
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 README file.
Task 1: Set up the test environment
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 and run the image on your local workstation.
1. Pull the Blockstack core clarity-developer-preview image from Docker Hub.
$ docker pull blockstack/blockstack-core:clarity-developer-preview2. Start the Blockstack Core test environment with a Bash shell.$ docker run -it -v $HOME/blockstack-dev-data:/data/ blockstack/blockstack-core:clarity-developer-preview bash
The 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.
root@f88368ba07b2:/src/blockstack-core# ls sample-programs/ names.clar tokens.clar
The sample programs directory contains two simple Clarity programs. Clarity code files have a .clar suffix.
4. Go ahead and display the contents of the tokens.clar program with the cat command.root@c28600552694:/src/blockstack-core# cat sample-programs/tokens.clarThe 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 line of the tokens.clar program contains a user-defined get-balance function.
(define (get-balance (account principal))
(default-to 0 (get balance (fetch-entry tokens (tuple (account account))))))
get-balance is a private function because it is constructed with the define 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..
(define (token-credit! (account principal) (tokens int))
(if (<= tokens 0)
(err "must move positive balance")
(let ((current-amount (get-balance account)))
(begin
(set-entry! tokens (tuple (account account))
(tuple (balance (+ tokens current-amount))))
(ok tokens)))))
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.
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 isa a globally defined variable that represents the the current principal.
(define-public (token-transfer (to principal) (amount int))
(let ((balance (get-balance tx-sender)))
(if (or (> amount balance) (<= amount 0))
(err "must transfer positive balance and possess funds")
(begin
(set-entry! tokens (tuple (account tx-sender))
(tuple (balance (- balance amount))))
(token-credit! to amount)))))
(define-public (mint! (amount int))
(let ((balance (get-balance tx-sender)))
(token-credit! tx-sender amount)))
(token-credit! 'SZ2J6ZY48GV1EZ5V2V5RB9MP66SW86PYKKQ9H6DPR 10000)
(token-credit! 'SM2J6ZY48GV1EZ5V2V5RB9MP66SW86PYKKQVX8X0G 300)
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 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 names.clar file.
cat names.clar
Which tokens.clar function is being called?
Task 3: Initialize data-space and launch contracts
1. In this task, you interact with the the contracts using the clarity-cli command line.
Initialize a new db database in the /data/ directory
# clarity-cli initialize /data/db
Database created
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.
2. Type check the names.clar contract.
# clarity-cli check sample-programs/names.clar /data/db
You should get an error:Type check error. NoSuchContract("tokens")This happens because the names.clar contract calls the tokens.clar contract, and that contract has not been created on the blockchain.
3. Type check the tokens.clar contract, it should pass a check as it does not use the contract-call function:
# clarity-cli check sample-programs/tokens.clar /data/db
Checks passed.When the check command executes successfully and exits with the stand UNIX 0 exit code.
4. Launch the tokens.clar contract.
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.
# clarity-cli launch 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.
5. Recheck the names.clar contract. # clarity-cli check sample-programs/names.clar /data/db
The program should pass validation because its dependency on tokens.clar is fulfilled.
6. Instantiate the names.clar contract as well.
# clarity-cli launch names sample-programs/names.clar /data/dbTask 4. Examine the SQLite database
The test environment uses a SQLite database to represent the blockchain. You initialized this database when you ran this earlier:
clarity-cli initialize /data/dbAs you work the contracts, data is added to the db database because you pass this database as a parameter, for example:
clarity-cli launch tokens sample-programs/tokens.clar /data/db
The database exists on your local workstation and persists through restarts of the container. You can use this database to examine the effects of your Clarity programs. The tables in the SQLite database are the following:
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 maps_table contains after you initialize the tokens contract.
sqlite> select * from maps_table;
1|tokens|tokens|{"Atom":{"TupleType":{"type_map":{"account":{"Atom":"PrincipalType"}}}}}|{"Atom":{"TupleType":{"type_map":{"balance":{"Atom":"IntType"}}}}}
sqlite>
Task 5: Execute a public function
In this section, you use the public mint! function in the tokens contract to mint some new tokens.
1. Use the clarity_cli command to create a demo address.
# clarity-cli generate_address SP26CHZZ26Q25WDD1CFJYSED169PS9HTNX445XKDG
2. Add the address to your environment.
# DEMO_ADDRESS=SP26CHZZ26Q25WDD1CFJYSED169PS9HTNX445XKDG
3. Get the current balance of your new address.
# echo "(get-balance '$DEMO_ADDRESS)" | clarity-cli eval tokens /data/db Program executed successfully! Output: 0
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.
4. Try minting some tokens and sending them to an address we’ll use for our demo.
# clarity-cli execute /data/db tokens mint! $DEMO_ADDRESS 100000
This executes the public mint! function defined in the tokens contract, sending 100000 tokens to you $DEMO_ADDRESS.
5. Use the clarity-cli eval command to check the result of this call.
# echo "(get-balance '$DEMO_ADDRESS)" | clarity-cli eval tokens /data/db Program executed successfully! Output: 100000
Task 6: Spend tokens by registering a name
Now, let’s register a name using the names.clar contract. Names are just integers in this sample contract, so you’ll register the name 10.
Compute the hash of the name we want to register.
You’ll salt the hash with the salt 8888:
# echo "(hash160 (xor 10 8888))" | clarity-cli eval names /data/db
Program executed successfully! Output:
0xb572fb1ce2e9665f1efd0994fe077b50c3a48fde
The value of the name hash is:
0xb572fb1ce2e9665f1efd0994fe077b50c3a48fde2. Preorder the name using the execute command:# clarity-cli execute /data/db names preorder $DEMO_ADDRESS 0xb572fb1ce2e9665f1efd0994fe077b50c3a48fde 1000
Transaction executed and committed. Returned: 0This 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).
3. Check the demo address’ new balance:# echo "(get-balance '$DEMO_ADDRESS)" | clarity-cli eval tokens /data/db
Program executed successfully! Output:
99000
4. Register the name by executing the register function:
# clarity-cli execute /data/db names register $DEMO_ADDRESS \'$DEMO_ADDRESS 10 8888
Transaction executed and committed. Returned: 0clarity-cli execute /data/db names register $DEMO_ADDRESS \'$DEMO_ADDRESS 10 8888
5. Lookup the “owner address” for the name:
# echo "(get owner (fetch-entry name-map (tuple (name 10))))" | clarity-cli eval names /data/db Program executed successfully! Output: (some 'SP26CHZZ26Q25WDD1CFJYSED169PS9HTNX445XKDG)
view all
Before you begin (pre-requisites)
Task 1: Set up the test environment
Task 2: Review a simple Clarity program
Task 3: Initialize data-space and launch contracts
Task 4. Examine the SQLite database
Task 5: Execute a public function
Task 6: Spend tokens by registering a name
Before you begin (pre-requisites)
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 Docker installed on your workstation.
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 README file.
Task 1: Set up the test environment
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 and run the image on your local workstation.
1. Pull the Blockstack core clarity-developer-preview image from Docker Hub.
$ docker pull blockstack/blockstack-core:clarity-developer-preview2. Start the Blockstack Core test environment with a Bash shell.
$ docker run -it -v $HOME/blockstack-dev-data:/data/ blockstack/blockstack-core:clarity-developer-preview bash
The 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.
root@f88368ba07b2:/src/blockstack-core# ls sample-programs/ names.clar tokens.clar
The sample programs directory contains two simple Clarity programs. Clarity code files have a .clar suffix.
4. Go ahead and display the contents of the tokens.clar program with the cat command.
root@c28600552694:/src/blockstack-core# cat sample-programs/tokens.clarThe 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 line of the tokens.clar program contains a user-defined get-balance function.
(define (get-balance (account principal))get-balance is a private function because it is constructed with the define 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.
(default-to 0 (get balance (fetch-entry tokens (tuple (account account))))))
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..
(define (token-credit! (account principal) (tokens int))
(if (<= tokens 0)
(err "must move positive balance")
(let ((current-amount (get-balance account)))
(begin
(set-entry! tokens (tuple (account account))
(tuple (balance (+ tokens current-amount))))
(ok tokens)))))
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.
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 isa a globally defined variable that represents the the current principal.
(define-public (token-transfer (to principal) (amount int))
(let ((balance (get-balance tx-sender)))
(if (or (> amount balance) (<= amount 0))
(err "must transfer positive balance and possess funds")
(begin
(set-entry! tokens (tuple (account tx-sender))
(tuple (balance (- balance amount))))
(token-credit! to amount)))))
(define-public (mint! (amount int))
(let ((balance (get-balance tx-sender)))
(token-credit! tx-sender amount)))
(token-credit! 'SZ2J6ZY48GV1EZ5V2V5RB9MP66SW86PYKKQ9H6DPR 10000)
(token-credit! 'SM2J6ZY48GV1EZ5V2V5RB9MP66SW86PYKKQVX8X0G 300)
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 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 names.clar file.
cat names.clar
Which tokens.clar function is being called?
Task 3: Initialize data-space and launch contracts
1. In this task, you interact with the the contracts using the clarity-cli command line.
Initialize a new db database in the /data/ directory
# clarity-cli initialize /data/dbYou 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.
Database created
2. Type check the names.clar contract.
# clarity-cli check sample-programs/names.clar /data/db
You should get an error:
Type check error. NoSuchContract("tokens")This happens because the names.clar contract calls the tokens.clar contract, and that contract has not been created on the blockchain.3. Type check the tokens.clar contract, it should pass a check as it does not use the contract-call function:
# clarity-cli check sample-programs/tokens.clar /data/dbWhen the check command executes successfully and exits with the stand UNIX 0 exit code.
Checks passed.
4. Launch the tokens.clar contract.
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.
# clarity-cli launch 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.
5. Recheck the names.clar contract.
# clarity-cli check sample-programs/names.clar /data/db
The program should pass validation because its dependency on tokens.clar is fulfilled.
6. Instantiate the names.clar contract as well.
# clarity-cli launch names sample-programs/names.clar /data/dbTask 4. Examine the SQLite database
The test environment uses a SQLite database to represent the blockchain. You initialized this database when you ran this earlier:
clarity-cli initialize /data/dbAs you work the contracts, data is added to the db database because you pass this database as a parameter, for example:
clarity-cli launch tokens sample-programs/tokens.clar /data/db
The database exists on your local workstation and persists through restarts of the container. You can use this database to examine the effects of your Clarity programs. The tables in the SQLite database are the following:

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 maps_table contains after you initialize the tokens contract.
sqlite> select * from maps_table;
1|tokens|tokens|{"Atom":{"TupleType":{"type_map":{"account":{"Atom":"PrincipalType"}}}}}|{"Atom":{"TupleType":{"type_map":{"balance":{"Atom":"IntType"}}}}}
sqlite>
Task 5: Execute a public function
In this section, you use the public mint! function in the tokens contract to mint some new tokens.
1. Use the clarity_cli command to create a demo address.
# clarity-cli generate_address SP26CHZZ26Q25WDD1CFJYSED169PS9HTNX445XKDG
2. Add the address to your environment.
# DEMO_ADDRESS=SP26CHZZ26Q25WDD1CFJYSED169PS9HTNX445XKDG
3. Get the current balance of your new address.
# echo "(get-balance '$DEMO_ADDRESS)" | clarity-cli eval tokens /data/db Program executed successfully! Output: 0
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.
4. Try minting some tokens and sending them to an address we’ll use for our demo.
# clarity-cli execute /data/db tokens mint! $DEMO_ADDRESS 100000
This executes the public mint! function defined in the tokens contract, sending 100000 tokens to you $DEMO_ADDRESS.
5. Use the clarity-cli eval command to check the result of this call.
# echo "(get-balance '$DEMO_ADDRESS)" | clarity-cli eval tokens /data/db Program executed successfully! Output: 100000
Task 6: Spend tokens by registering a name
Now, let’s register a name using the names.clar contract. Names are just integers in this sample contract, so you’ll register the name 10.
Compute the hash of the name we want to register.
You’ll salt the hash with the salt 8888:
# echo "(hash160 (xor 10 8888))" | clarity-cli eval names /data/db
Program executed successfully! Output:
0xb572fb1ce2e9665f1efd0994fe077b50c3a48fde
The value of the name hash is:
0xb572fb1ce2e9665f1efd0994fe077b50c3a48fde2. Preorder the name using the execute command:
# clarity-cli execute /data/db names preorder $DEMO_ADDRESS 0xb572fb1ce2e9665f1efd0994fe077b50c3a48fde 1000This 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).
Transaction executed and committed. Returned: 0
3. Check the demo address’ new balance:
# echo "(get-balance '$DEMO_ADDRESS)" | clarity-cli eval tokens /data/db
Program executed successfully! Output:
99000
4. Register the name by executing the register function:
# clarity-cli execute /data/db names register $DEMO_ADDRESS \'$DEMO_ADDRESS 10 88885. Lookup the “owner address” for the name:
Transaction executed and committed. Returned: 0clarity-cli execute /data/db names register $DEMO_ADDRESS \'$DEMO_ADDRESS 10 8888
# echo "(get owner (fetch-entry name-map (tuple (name 10))))" | clarity-cli eval names /data/db Program executed successfully! Output: (some 'SP26CHZZ26Q25WDD1CFJYSED169PS9HTNX445XKDG)
How to use Clarity smart contract language to define functions and data maps
Others • blockstack app store posted the article • 0 comments • 1722 views • 2019-06-28 00:59
define and define-public functions
define-read-only functions
define-map functions for data
List operations and functions
Intra-contract calls
Reading from other smart contracts
define and define-public functions
Functions specified via define-public statements are public functions. Functions without these designations, simple define statements, are private functions. You can run a contract’s public functions directly via the clarity-cli execute command line directly or from other contracts. You can use the clarity eval or clarity eval_raw commands to evaluate private functions via the command line.
Public functions return a Response type result. If the function returns an ok type, then the function call is considered valid, and any changes made to the blockchain state will be materialized. If the function returns an err type, it is considered invalid, and has no effect on the smart contract’s state.
For example, consider two functions, foo.A and bar.B where the foo.A function calls bar.B, the table below shows the data materialization that results from the possible combination of return values:
Defining of constants and functions are allowed for simplifying code using a define statement. However, these are purely syntactic. If a definition cannot be inlined, the contract is rejected as illegal. These definitions are also private, in that functions defined this way may only be called by other functions defined in the given smart contract.
define-read-only functions
Functions specified via define-read-only statements are public. Unlike functions created by define-public, functions created with define-read-only may return any type. However, define-read-only statements cannot perform state mutations. Any attempts to modify contract state by these functions or functions called by these functions result in an error.
define-map functions for data
Data within a smart contract’s data-space is stored within maps. These stores relate a typed-tuple to another typed-tuple (almost like a typed key-value store). As opposed to a table data structure, a map only associates a given key with exactly one value. A smart contract defines the data schema of a data map with the define-map function.
(define-map map-name ((key-name-0 key-type-0) ...) ((val-name-0 val-type-0) ...))
Clarity contracts can only call the define-map function in the top-level of the smart-contract (similar to define. This function accepts a name for the map, and a definition of the structure of the key and value types. Each of these is a list of (name, type) pairs. Types are either the values 'principal, 'integer, 'bool or the output of one of the hash calls which is an n-byte fixed-length buffer.
To support the use of named fields in keys and values, Clarity allows the construction of tuples using a function (tuple ((key0 expr0) (key1 expr1) ...)), for example:
(tuple (name "blockstack") (id 1337))
This allows for creating named tuples on the fly, which is useful for data maps where the keys and values are themselves named tuples. To access a named value of a given tuple, the function (get #name tuple) will return that item from the tuple.
The define-map interface, as described, disallows range-queries and queries-by-prefix on data maps. Within a smart contract function, you cannot iterate over an entire map. Values in a given mapping are set or fetched using the following functions:
Data maps make reasoning about functions easier. By inspecting a given function definition, it is clear which maps will be modified and, even within those maps, which keys are affected by a given invocation. Also, the interface of data maps ensures that the return types of map operations are fixed length; Fixed length returns is a requirement for static analysis of a contract’s runtime, costs, and other properties.
List operations and functions
Lists may be multi-dimensional. However, note that runtime admission checks on typed function-parameters and data-map functions like set-entry! are charged based on the maximal size of the multi-dimensional list.
You can call filter map and fold functions with user-defined functions (that is, functions defined with (define ...), (define-read-only ...), or (define-public ...)) or simple, native functions (for example, +, -, not).
Intra-contract calls
A smart contract may call functions from other smart contracts using a (contract-call!) function:(contract-call! contract-name function-name arg0 arg1 ...)
This function accepts a function name and the smart contract’s name as input. For example, to call the function token-transfer in the smart contract, you would use:
(contract-call! tokens token-transfer burn-address name-price))
For intra-contract calls dynamic dispatch is not supported. When a contract is launched, any contracts it depends on (calls) must exist. Additionally, no cycles may exist in the call graph of a smart contract. This prevents recursion (and re-entrancy bugs. A static analysis of the call graph detects such structures and they are rejected by the network.
A smart contract may not modify other smart contracts’ data directly; it can read data stored in those smart contracts’ maps. This read ability does not alter any confidentiality guarantees of Clarity. All data in a smart contract is inherently public, andis readable through querying the underlying database in any case.
Reading from other smart contracts
To read another contract’s data, use (fetch-contract-entry) function. This behaves identically to (fetch-entry), though it accepts a contract principal as an argument in addition to the map name:
(fetch-contract-entry
'contract-name
'map-name
'key-tuple) ;; value tuple or none
For example, you could do this:
(fetch-contract-entry
names
name-map
1) ;;returns owner principal of name
Just as with the (contract-call) function, the map name and contract principal arguments must be constants, specified at the time of publishing.
Finally, and importantly, the tx-sender variable does not change during inter-contract calls. This 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. This enables a wide variety of applications, but it comes with some dangers for users of smart contracts. However, the static analysis guarantees of Clarity allow clients to know a priori which functions a given smart contract will ever call. Good clients should always warn users about any potential side effects of a given transaction.
view all
define and define-public functions
define-read-only functions
define-map functions for data
List operations and functions
Intra-contract calls
Reading from other smart contracts
define and define-public functions
Functions specified via define-public statements are public functions. Functions without these designations, simple define statements, are private functions. You can run a contract’s public functions directly via the clarity-cli execute command line directly or from other contracts. You can use the clarity eval or clarity eval_raw commands to evaluate private functions via the command line.
Public functions return a Response type result. If the function returns an ok type, then the function call is considered valid, and any changes made to the blockchain state will be materialized. If the function returns an err type, it is considered invalid, and has no effect on the smart contract’s state.
For example, consider two functions, foo.A and bar.B where the foo.A function calls bar.B, the table below shows the data materialization that results from the possible combination of return values:

Defining of constants and functions are allowed for simplifying code using a define statement. However, these are purely syntactic. If a definition cannot be inlined, the contract is rejected as illegal. These definitions are also private, in that functions defined this way may only be called by other functions defined in the given smart contract.
define-read-only functions
Functions specified via define-read-only statements are public. Unlike functions created by define-public, functions created with define-read-only may return any type. However, define-read-only statements cannot perform state mutations. Any attempts to modify contract state by these functions or functions called by these functions result in an error.
define-map functions for data
Data within a smart contract’s data-space is stored within maps. These stores relate a typed-tuple to another typed-tuple (almost like a typed key-value store). As opposed to a table data structure, a map only associates a given key with exactly one value. A smart contract defines the data schema of a data map with the define-map function.
(define-map map-name ((key-name-0 key-type-0) ...) ((val-name-0 val-type-0) ...))
Clarity contracts can only call the define-map function in the top-level of the smart-contract (similar to define. This function accepts a name for the map, and a definition of the structure of the key and value types. Each of these is a list of (name, type) pairs. Types are either the values 'principal, 'integer, 'bool or the output of one of the hash calls which is an n-byte fixed-length buffer.
To support the use of named fields in keys and values, Clarity allows the construction of tuples using a function (tuple ((key0 expr0) (key1 expr1) ...)), for example:
(tuple (name "blockstack") (id 1337))
This allows for creating named tuples on the fly, which is useful for data maps where the keys and values are themselves named tuples. To access a named value of a given tuple, the function (get #name tuple) will return that item from the tuple.
The define-map interface, as described, disallows range-queries and queries-by-prefix on data maps. Within a smart contract function, you cannot iterate over an entire map. Values in a given mapping are set or fetched using the following functions:

Data maps make reasoning about functions easier. By inspecting a given function definition, it is clear which maps will be modified and, even within those maps, which keys are affected by a given invocation. Also, the interface of data maps ensures that the return types of map operations are fixed length; Fixed length returns is a requirement for static analysis of a contract’s runtime, costs, and other properties.
List operations and functions
Lists may be multi-dimensional. However, note that runtime admission checks on typed function-parameters and data-map functions like set-entry! are charged based on the maximal size of the multi-dimensional list.
You can call filter map and fold functions with user-defined functions (that is, functions defined with (define ...), (define-read-only ...), or (define-public ...)) or simple, native functions (for example, +, -, not).
Intra-contract calls
A smart contract may call functions from other smart contracts using a (contract-call!) function:
(contract-call! contract-name function-name arg0 arg1 ...)
This function accepts a function name and the smart contract’s name as input. For example, to call the function token-transfer in the smart contract, you would use:
(contract-call! tokens token-transfer burn-address name-price))
For intra-contract calls dynamic dispatch is not supported. When a contract is launched, any contracts it depends on (calls) must exist. Additionally, no cycles may exist in the call graph of a smart contract. This prevents recursion (and re-entrancy bugs. A static analysis of the call graph detects such structures and they are rejected by the network.
A smart contract may not modify other smart contracts’ data directly; it can read data stored in those smart contracts’ maps. This read ability does not alter any confidentiality guarantees of Clarity. All data in a smart contract is inherently public, andis readable through querying the underlying database in any case.
Reading from other smart contracts
To read another contract’s data, use (fetch-contract-entry) function. This behaves identically to (fetch-entry), though it accepts a contract principal as an argument in addition to the map name:
(fetch-contract-entry
'contract-name
'map-name
'key-tuple) ;; value tuple or none
For example, you could do this:
(fetch-contract-entry
names
name-map
1) ;;returns owner principal of name
Just as with the (contract-call) function, the map name and contract principal arguments must be constants, specified at the time of publishing.
Finally, and importantly, the tx-sender variable does not change during inter-contract calls. This 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. This enables a wide variety of applications, but it comes with some dangers for users of smart contracts. However, the static analysis guarantees of Clarity allow clients to know a priori which functions a given smart contract will ever call. Good clients should always warn users about any potential side effects of a given transaction.
Principals-a Clarity (smart contract language for blockstack dapps)native type
Others • blockstack app store posted the article • 0 comments • 1497 views • 2019-06-28 00:49
Principals and tx-sender
A principal is represented by a public-key hash or multi-signature Stacks address. Assets in Clarity and the Stacks blockchain are “owned” by objects of the principal type; put another way, principal object types may own an asset.
A given principal operates on its assets by issuing a signed transaction on the Stacks blockchain. A Clarity contract can use a globally defined tx-sender variable to obtain the current principal.
The following user-defined function transfers an asset, in this case, tokens, between two principals:
(define (transfer! (sender principal) (recipient principal) (amount int))
(if (and
(not (eq? sender recipient))
(debit-balance! sender amount)
(credit-balance! recipient amount))
'true
'false))
The principal’s signature is not checked by the smart contract, but by the virtual machine.
Smart contracts as principals
Smart contracts themselves are principals and are represented by the smart contract’s identifier. You create the identifier when you launch the contract, for example, the contract identifier here is hanomine.
clarity-cli launch hanomine /data/hano.clar /data/db
A smart contract may use the special variable contract-name to refer to its own principal.
To allow smart contracts to operate on assets it owns, smart contracts may use the special (as-contract expr) function. This function executes the expression (passed as an argument) with the tx-sender set to the contract’s principal, rather than the current sender. The as-contract function returns the value of the provided expression.
For example, a smart contract that implements something like a “token faucet” could be implemented as so:
(define-public (claim-from-faucet)
(if (is-none? (fetch-entry claimed-before (tuple (sender tx-sender))))
(let ((requester tx-sender)) ;; set a local variable requester = tx-sender
(begin
(insert-entry! claimed-before (tuple (sender requester)) (tuple (claimed 'true)))
(as-contract (stacks-transfer! requester 1)))))
(err 1))
In this example, the public function claim-from-faucet:
Checks if the sender has claimed from the faucet before.Assigns the tx sender to a requester variable.Adds an entry to the tracking map.Uses as-contract to send 1 microstack
Contract writers can use the primitive function is-contract? to determine whether a given principal corresponds to a smart contract.
Unlike other principals, there is no private key associated with a smart contract. As it lacks a private key, a Clarity smart contract cannot broadcast a signed transaction on the blockchain.
view all
Principals and tx-sender
A principal is represented by a public-key hash or multi-signature Stacks address. Assets in Clarity and the Stacks blockchain are “owned” by objects of the principal type; put another way, principal object types may own an asset.
A given principal operates on its assets by issuing a signed transaction on the Stacks blockchain. A Clarity contract can use a globally defined tx-sender variable to obtain the current principal.
The following user-defined function transfers an asset, in this case, tokens, between two principals:
(define (transfer! (sender principal) (recipient principal) (amount int))
(if (and
(not (eq? sender recipient))
(debit-balance! sender amount)
(credit-balance! recipient amount))
'true
'false))
The principal’s signature is not checked by the smart contract, but by the virtual machine.
Smart contracts as principals
Smart contracts themselves are principals and are represented by the smart contract’s identifier. You create the identifier when you launch the contract, for example, the contract identifier here is hanomine.
clarity-cli launch hanomine /data/hano.clar /data/db
A smart contract may use the special variable contract-name to refer to its own principal.
To allow smart contracts to operate on assets it owns, smart contracts may use the special (as-contract expr) function. This function executes the expression (passed as an argument) with the tx-sender set to the contract’s principal, rather than the current sender. The as-contract function returns the value of the provided expression.
For example, a smart contract that implements something like a “token faucet” could be implemented as so:
(define-public (claim-from-faucet)
(if (is-none? (fetch-entry claimed-before (tuple (sender tx-sender))))
(let ((requester tx-sender)) ;; set a local variable requester = tx-sender
(begin
(insert-entry! claimed-before (tuple (sender requester)) (tuple (claimed 'true)))
(as-contract (stacks-transfer! requester 1)))))
(err 1))
In this example, the public function claim-from-faucet:
- Checks if the sender has claimed from the faucet before.
- Assigns the tx sender to a requester variable.
- Adds an entry to the tracking map.
- Uses as-contract to send 1 microstack
Contract writers can use the primitive function is-contract? to determine whether a given principal corresponds to a smart contract.
Unlike other principals, there is no private key associated with a smart contract. As it lacks a private key, a Clarity smart contract cannot broadcast a signed transaction on the blockchain.
Clarity-Blockstack smart contract language tutorials and docs
Others • blockstack app store posted the article • 0 comments • 1757 views • 2019-06-28 00:38
Who should use smart contracts?
Language and program design
The coding environment
Basic building blocks of Clarity contracts
hello-world example
Language rules and limitations
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.
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.
Not every application requires smart contracts. If you are not sure or are new to smart contracts concepts, you should read ]a good general explanation of smart contracts[/url] before working with Clarity.
Language and program design
Clarity differs from most other smart contract languages in two essential ways:
The language is not intended to be compiled.The language is not Turing complete.
These differences allow for static analysis of programs to determine properties like runtime cost and data usage.
A Clarity smart contract is composed of two parts — 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.
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.
The coding environment
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. 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.
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-sender10000SZ2J6ZY48GV1EZ5V2V5RB9MP66SW86PYKKQ9H6DPR
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.
;; 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.
(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:
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.
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:
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:
The only atomic types are booleans, integers, fixed length buffers, and principalsRecursion is illegal and there is no lambda function.Looping may only be performed via map, filter, or foldThere 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.
view all
Who should use smart contracts?
Language and program design
The coding environment
Basic building blocks of Clarity contracts
hello-world example
Language rules and limitations
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.
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.
Not every application requires smart contracts. If you are not sure or are new to smart contracts concepts, you should read ]a good general explanation of smart contracts[/url] before working with Clarity.
Language and program design
Clarity differs from most other smart contract languages in two essential ways:
- The language is not intended to be compiled.
- The language is not Turing complete.
These differences allow for static analysis of programs to determine properties like runtime cost and data usage.
A Clarity smart contract is composed of two parts — 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.
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.
The coding environment
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. 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.
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.
;; 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.
(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:
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.
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:
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:
- The only atomic types are booleans, integers, fixed length buffers, and principals
- Recursion is illegal and there is no lambda function.
- Looping may only be performed via map, filter, or fold
- 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.
- Clarity-Blockstack smart contract language tutorials and docs
- 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).