Clarity notes
- 1. Software
- 2. Basics
- 3.Types
- 4. Keywords
- 5. Storing data
- 6. Functions
- 7. Control flow functions
- 8 NFTs and FTs
- 9 Traits
- 10. Miscellaneous
- 11. Deploy a contract on tesnet
1. Software
- Clarity extension for Visual Studio Code - This link provides a more updated version than if installed directly from OSS
- Clarity REPL - I prefer to build it from source
- Copy latest release of Clarinet into
/usr/local/bin/
(linux users). - Clarity Tools
1.2 Clarinet
clarinet new my-project && cd my-project ;; Create a new project
clarinet contract new mycoolcontract ;; Create new contract in project
clarinet check ;; Check the syntax of Clarity
clarinet test ;; Test
clarinet console ;;
clarinet integrate ;; Launch Devnet with default configuration
Clarity.toml
(configuration file of the project), contains a reference to contract files and dependencies.
Files in settings
are used for deployment:
- Devnet.toml - configuration used for tests and console mode.
- Mocknet.toml
- Mainnet.toml
1.2.1.Clarinet console
In the clarinet console you have multiple useful commands like:
(contract-call? contract-identifier function-name param-1 param-2 ...)
::set_tx_sender ST1SJ3DTE5DN7X54YDH5D64R3BCB6A2AG2ZQ8YPD5
::get_assets_maps
In REPLC blocks dont increment by themselves so if needed we can simulate mining with ::advance_chain_tip 10
, that will increment the block height with 10.
2. Basics
;; Comments start with 2 semicolons.
(concat "Hello" " World!") ;;
3.Types
Types are strictly enforced and can’t be mixed: (+ 2 u3)
isn’t accepted.
3 categories of types: Primitives, Sequences and Composites.
3.1 Type: Primitives
These are signed and unsigned integers, booleans and principals
(* 4 (+ 15 10));; The result is 100.
(/ u99 u100) ;; Decimals are dropped not rounded up. The result will be 0.
(not true) ;; Inverts a boolean. The result is false
(and true true true) ;; 'and' returns true if all inputs are true. The result is true.
(or false true false) ;; 'or' returns true if at least one input is true. The result is true.
Principals
Represent a Stacks address on the blockchain.
'ST1HTBVD3JG9C05J7HBJTHGR0GGW7KXW28M5JS8QE ;; A Stacks address
'ST1HTBVD3JG9C05J7HBJTHGR0GGW7KXW28M5JS8QE.my-awesome-contract ;; A Stacks contract
(stx-get-balance 'ST1HTBVD3JG9C05J7HBJTHGR0GGW7KXW28M5JS8QE) ;; Checks balance of a Stacks address
3.2 Type: Sequences
3 types of sequences:
buffers:
;; Buffers start with 0x followed by a hexadecimal string
0x68656c6c6f21
strings:
"ACII string"
u"UTF-8 string"
lists:
(list 4 8 15 16 23 42) ;; Types cannot mix in a list
(list "Hello" "World" "!")
;; map applies an input function to each element
(map not (list true true false false)) ;; This returns [false false true true]
;; fold applies an input function to each element AND the output value of the previous application
(fold + (list u1 u2 u3) u4) ;; This returns 10
(len "How long is this string?")
;; Position counts start at 0
;; Functions that might or might not return a value tend to return an optional type named `some`
(element-at (list 4 8 15 16 23 42) u3) ;; Returns (some 16)
(index-of (list 4 8 15 16 23 42) 23) ;; Returns (some u4)
(index-of (list 4 8 15 16 23 42) 24) ;; Returns none
3.3 Type: Composites
Optionals
The type system in Clarity does not allow for empty values, so an integer always contains a number. To express a variable that could have some value or nothing we use the keyword some.
(some u5)
(some "An optional containing a string.")
;; To access the value contained within an optional, you have to unwrap it first:
(unwrap-panic (some u10)) ;; Returns (some u10)
Tuples
;; Declare a tuple
{
id: u5, ;; a uint
username: "ClarityIsAwesome", ;; an ASCI string
address: 'ST1HTBVD3JG9C05J7HBJTHGR0GGW7KXW28M5JS8QE ;; and a principal
}
;; Get a value in a tuple:
(get username { id: 5, username: "bob" }) ;; Returns bob
;;Merge (to change) a tuple:
(merge
{id: 5, score: 10, username: "bob"}
{score: u20, active: true}
)
;; Returns {id: 5, score: 20, username: "bob", active: true}
Responses
;; Responses can be 'ok' or 'err'
(err u5)
(ok true)
(unwrap-panic (ok true)) ;; Returns true
Using the err
response type we can be sure than any changes will revert if the error is called for.
3.4 Type Signatures
Type signature define the admitted type for variable or function argument
Type | Signature |
---|---|
Buffer | (buff max-len) |
ASCII string | (string-ascii max-len) |
UTF-8 string | (string-utf8 max-len) |
List | (list max-len element-type) |
Optional | (optional some-type) |
Tuple | {key1: type1, key2: type2} |
Response | (response ok-type err-type) |
4. Keywords
List of all keywords in Clarity
block-height ;; Stacks block number
burn-block-height ;; Bitcoin's block number
tx-sender ;; Principal that sent the transaction
(as-contract tx-sender)
contract-caller ;; Contains the principal that called the function. It can be a standard principal or contract principal. If the contract is called via a signed transaction directly, then tx-sender and contract-caller will be the same. If the contract calls another contract in turn, then contract-caller will be equal to the previous contract in the chain.
contract-owner ;; Contains
5. Storing data
3 kinds of storage: Constants, Variables and Maps
5.1 Storing data: Constants
(define-constant my-constant "This is a constant")
(print my-constant)
5.2 Storing data: Variables
(define-data-var my-number uint u0)
(print (var-get my-number)) ;; Print the value
(var-set my-number u5000) ;; Change the value
5.3 Storing data: Maps
Maps are hash tables.
Maps are not iterable, you cannot loop though it to retrieve all values. The only way to access a value in a map is to enter the key.
(define-map map-name key-type value-type)
Set and delete values:
(map-set map-name tx-sender u100) ;; map-set sets or overwrites a value
(map-insert map-name tx-sender u100) ;; map-insert fails if the key already exists
(map-delete map-name tx-sender)
Retrieve value:
(print (map-get? invoice u1))
Another more complex map:
(define-map listings
uint
{
maker: principal,
taker: (optional principal),
token-id: uint
}
)
6. Functions
3 kinds of functions: list of functions:
Public functions | Private functions | Read-only functions |
---|---|---|
Can be called externally. | Only called by the current contract | Can be called externally, |
Calls require sending a transaction (fees). | but may not change the chain state (no fees) |
(define-public function-signature function-body)
** Function signature ** Defines the name of the function and any input parameters.
(function-name (param1-name param1-type) (param2-name param2-type) ...)
Example:
(define-public (hello (name (string-ascii 30)))
(ok (concat "Hola " name))
)
(print (hello "Clarity"))
** Function body ** The variadic begin function takes an arbitrary amount of inputs and will return the result of the last expression.
(define-public (print-twice (first (string-ascii 40)) (second (string-ascii 40)))
(begin
(print first)
(print second)
(ok true)
)
)
(print-twice "Hello world!" "Multiple prints!")
Outputs:
"Hello world!"
"Multiple prints!"
7. Control flow functions
7.1 asserts!
If the boolean expression evaluates to true, then asserts! returns true and execution continues, but if the expression evaluates to false then asserts! will return the throw value and exit the current control flow.
(asserts! boolean-expression throw-value)
7.2 try!
The try!
function takes an optional or a response type and will attempt to unwrap it.
(try! (some "wrapped string"))
try! can only unwrap some
and ok
values.
If it receives a none
or an err
, it will return it and exit the current control flow.
7.3 unwrap
The unwrap
function takes an optional
or a response
type and will attempt to unwrap it, same as try!
, but instead of propagating the none
or the err
it will return the throw value instead.
(unwrap! (some "wrapped string") (err "unwrap failed"))
7.4 unwrap-err!
Take a response
type and if its and err
it will return the wrapped value, if not returns the throw value and exits.
7.5 unwrap-panic
Takes an optional
or a response
type and if it fails to unwarp it throws a runtime error and exists the current flow.
(unwrap-panic (ok true))
7.6 unwrap-err-panic
The input is unwrapped if its is an err
, if not a runtime error in thrown
8 NFTs and FTs
8.1 SIP009: The NFT Standard
get-last-token-id
get-token-uri
get-owner
transfer
8.2 NFT stuff
(define-non-fungible-token asset-name identifier-type)
(nft-mint? asset-name toke-id recipient)
(nft-get-owner? asset-name token-id)
(nft-transfer? asset-name token-id sender recipient)
(nft-burn? asset-name token-id owner)
8.3 SIP010: The FT Standard
SIP010 defines the standard and is deployed to mainnet on:
SP3FBR2AGK5H9QBDH3EEN6DF8EK8JY7RX8QJ5SVTE.sip-010-trait-ft-standard
9 Traits
(define-trait my-trait
(
(function-name-1 (param-types-1) response-type-1)
(function-name-2 (param-types-2) response-type-2)
)
)
Latest NFT Trait on Mainnet according to SIP-009. They are older NFT Traits on Mainnet that shouldn’t be used anymore.
SIP-010 defined the Fungible Token Standard Trait on Mainnet.
I can implement a trait of another principal:
(impl-trait 'SP2PABAF9FTAJYNFZH93XENAJ8FVY99RRM50D2JG9.nft-trait.nft-trait
or one defined in the same one:
(impl-trait .multiplier-trait.multiplier)
In Clarinet.toml
, the property depends_on = ["contract1", "contract2]
contains the lists of contracts that a given contract depends on.
[contracts.mycoolcontract]
path = "contracts/mycoolcontract.clar"
depends_on = ["contract1", "contract2"]
(use-trait trait-alias trait-identifier)
(contract-call? .example-contract claim-wallet .timelocked-wallet)
10. Miscellaneous
is-eq: (is-eq a b)
returns true if a=b
is-none: (is-none a)
returns true if a is none (null).
>: (> a b)
return true is a > b.
block-height
returns block-height
(as-contract ...)
So a smart contract can operate on assets it owns. This function executes the expression that is passed as an argument, with the tx-sender set to the contract’s principal instead of the current sender.
let ()
In this example, match
conditionally calls print if the passed memo is some:
(match (some "inner string")
inner-str (print inner-str)
(print "got nothing")
)
11. Deploy a contract on tesnet
You can copy-paste and deploy here