Clarc
Clarc compiles Clarity smart contracts into Ethereum virtual machine (EVM) bytecode.
More specifically, the Clarc compiler, called clarc
, parses .clar
files and
compiles them into an equivalent EVM bytecode program that runs on the Ethereum
blockchain.
Note: Here be dragons. This is a pre-alpha, work-in-progress project. Assume nothing works, and you may be pleasantly surprised on occasion.
Installation
Binary Downloads
The latest release binaries for macOS and Linux are available here:
To install, just download and untar the archive and then copy the resulting
binary to /usr/local/bin
, as follows:
macOS
wget https://github.com/weavery/clarc/releases/download/0.5.0/clarc-0.5.0-macos.tar.gz
tar xf clarc-0.5.0-macos.tar.gz
sudo install clarc-0.5.0-macos /usr/local/bin/clarc
Linux
wget https://github.com/weavery/clarc/releases/download/0.5.0/clarc-0.5.0-linux.tar.gz
tar xf clarc-0.5.0-linux.tar.gz
sudo install clarc-0.5.0-linux /usr/local/bin/clarc
Source Code
If you wish to try out the latest and greatest Clarc, you will need to build it from source code yourself, which entails setting up an OCaml development environment. Reserve at least half an hour of time and see further down in this document for the particulars.
Usage
To view Clarc's built-in man page that documents all command-line options, run:
clarc --help
Compiling to opcode
To compile the Clarity counter.clar
example contract to programmer-readable
output, known as symbolic opcode, run:
clarc -t opcode counter.clar
The previous writes out the compiled program to standard output, which is helpful during development and debugging.
Compiling to bytecode
To compile the Clarity counter.clar
example contract to deployable
bytecode, run:
clarc -t bytecode counter.clar
Alternatively, you can specify an output file name in the usual way, with the
target type inferred from the output file extension (.bin
for bytecode,
in keeping with the Solidity compiler):
clarc -o counter.bin counter.clar
Deploying the contract
MyEtherWallet is the easiest way to deploy the generated contracts:
Examples
Supported Contracts
The currently tested contracts, deployed to the public Ropsten testnet, are:
Contract ID | Contract Code | Contract Bytecode | Contract ABI |
---|---|---|---|
0x8a90b1e93020933295b3bd4ce2317062319351d4 | counter.clar |
counter.bin |
counter.json |
0x2e2487c64b1420111e8d66d751f75f69515c5476 | kv-store.clar |
kv-store.bin |
kv-store.json |
0x9a1b29fc432af1e37af03ed2fee00d742ff7372f | panic.clar |
panic.bin |
panic.json |
MyEtherWallet is the easiest way to interact with these deployed contracts.
Example: Counter
counter.clar
(define-data-var counter int 0)
(define-read-only (get-counter)
(ok (var-get counter)))
(define-public (increment)
(begin
(var-set counter (+ (var-get counter) 1))
(ok (var-get counter))))
(define-public (decrement)
(begin
(var-set counter (- (var-get counter) 1))
(ok (var-get counter))))
counter.opcode
$ clarc counter.clar -t opcode
PUSH1 0x00 PUSH1 0x00 SSTORE PUSH1 0x64 DUP1 PUSH1 0x10 PUSH1 0x00 CODECOPY
PUSH1 0x00 RETURN PUSH1 0xe0 PUSH1 0x02 EXP PUSH1 0x00 CALLDATALOAD DIV DUP1
PUSH4 0x8ada066e EQ PUSH1 0x28 JUMPI DUP1 PUSH4 0xd09de08a EQ PUSH1 0x36
JUMPI DUP1 PUSH4 0x2baeceb7 EQ PUSH1 0x4d JUMPI STOP JUMPDEST POP PUSH1 0x00
SLOAD PUSH1 0x00 MSTORE PUSH1 0x20 PUSH1 0x00 RETURN STOP JUMPDEST POP
PUSH1 0x01 PUSH1 0x00 SLOAD ADD PUSH1 0x00 SSTORE PUSH1 0x00 SLOAD PUSH1 0x00
MSTORE PUSH1 0x20 PUSH1 0x00 RETURN STOP JUMPDEST POP PUSH1 0x01 PUSH1 0x00
SLOAD SUB PUSH1 0x00 SSTORE PUSH1 0x00 SLOAD PUSH1 0x00 MSTORE PUSH1 0x20
PUSH1 0x00 RETURN STOP
counter.bin
$ clarc counter.clar -t bytecode
600060005560648060106000396000f360e060020a6000350480638ada066e146028578063d09de08a1460365780632baeceb714604d57005b5060005460005260206000f3005b5060016000540160005560005460005260206000f3005b5060016000540360005560005460005260206000f300
Design
Clarc is written in OCaml, an excellent programming language for crafting compiler toolchains.
Clarc is a standard multi-pass compiler consisting of the following stages:
The Clarity parser and abstract syntax tree (AST) are maintained as a subproject in an OCaml library called Clarity.ml. The library enables anyone familiar with OCaml to quickly and easily develop more best-of-class tooling for Clarity contracts.
Lexical analysis
See Clarity.ml's lexer.mll
for the lexical analyzer source code.
Syntactic analysis
See Clarity.ml's parser.mly
and parse.ml
for the parser source code.
Semantic analysis
See Clarity.ml's grammar.ml
for the structure of the Clarity AST.
Development
This section documents how to get set up with a development environment for building Clarc from source code. It is only of interest to people who wish to contribute to Clarc.
Prerequisites
The following baseline tooling is required in order to build Clarc from source code:
We would recommend you don't install OCaml from a package manager.
Rather, get set up with OPAM and then let OPAM install the correct version of OCaml as follows:
opam init -c 4.11.1 # if OPAM not yet initialized
opam switch create 4.11.1 # if OPAM already initialized
Once OPAM and OCaml are available, install Dune as follows:
opam install dune
Dependencies
The following OCaml tools and libraries are required in order to build Clarc from source code:
-
Alcotest for unit tests
-
Clarity.ml for parsing Clarity code
-
Cmdliner for the command-line interface
-
Cppo for code preprocessing
-
Cryptokit for the Keccak-256 hash function
-
ISO8601 for date handling
-
Num for 128-bit integers
-
Ocolor for terminal colors
These aforementioned dependencies are all best installed via OPAM:
opam install -y alcotest cmdliner cppo cryptokit iso8601 num ocolor
opam pin add -y clarity-lang https://github.com/weavery/clarity.ml -k git
Running the program
alias clarc='dune exec bin/clarc/clarc.exe --'
clarc --help
Installing from source code
git clone https://github.com/weavery/clarc.git
cd clarc
dune build
sudo install _build/default/bin/clarc/clarc.exe /usr/local/bin/clarc
Acknowledgments
We thank the Stacks Foundation for sponsoring the development of Clarc.
We thank Blockstack and Algorand for having developed the Clarity language, an important evolution for the future of smart contracts.
Status
Supported Clarity features
Feature | Type | Status | Notes |
---|---|---|---|
* |
function | For two parameters. Without overflow checking. | |
+ |
function | For two parameters. Without overflow checking. | |
- |
function | For two parameters. Without underflow checking. | |
/ |
function | For two parameters. Without division-by-zero checking. | |
< |
function | ||
<= |
function | ||
> |
function | ||
>= |
function | ||
and |
operator | For two parameters. | |
append |
function | ||
as-contract |
operator | ||
as-max-len? |
operator | ||
asserts! |
function | ||
at-block |
operator | Not implemented yet. | |
begin |
operator | ||
block-height |
keyword | ||
buff |
literal | ||
burn-block-height |
keyword | ||
concat |
function | Only for lists. | |
contract-call? |
operator | Not implemented yet. | |
contract-caller |
keyword | ||
contract-of |
operator | Not implemented yet. | |
default-to |
function | ||
err |
function | ||
false |
literal | ||
filter |
function | ||
fold |
function | ||
ft-get-balance |
function | ||
ft-mint? |
function | ||
ft-transfer? |
function | ||
get |
operator | ||
get-block-info? |
operator | Not implemented yet. | |
hash160 |
function | ||
if |
operator | ||
impl-trait |
operator | Not implemented yet. | |
int |
literal | ||
is-eq |
function | For two parameters. | |
is-err |
function | ||
is-in-regtest |
keyword | ||
is-none |
function | ||
is-ok |
function | ||
is-some |
function | ||
keccak256 |
function | ||
len |
function | Only for literals. | |
let |
operator | ||
list |
function | ||
map |
function | ||
map-delete |
function | ||
map-get? |
function | ||
map-insert |
function | ||
map-set |
function | ||
match |
operator | ||
mod |
function | Without division-by-zero checking. | |
nft-get-owner? |
function | ||
nft-mint? |
function | ||
nft-transfer? |
function | ||
none |
literal | ||
not |
function | ||
ok |
function | ||
or |
operator | For two parameters. | |
pow |
function | Without overflow checking. | |
principal |
literal | ||
principal-of? |
function | ||
print |
function | Only for literals. Without a meaningful return value. | |
secp256k1-recover? |
function | Not implemented yet. | |
secp256k1-verify |
function | Not implemented yet. | |
sha256 |
function | ||
sha512 |
function | Not implemented yet. | |
sha512/256 |
function | Not implemented yet. | |
some |
function | ||
sqrti |
function | Not implemented yet. | |
string |
literal | ||
stx-burn? |
function | Not supported. | |
stx-get-balance |
function | Not supported. | |
stx-liquid-supply |
keyword | Not supported. | |
stx-transfer? |
function | Not supported. | |
to-int |
function | ||
to-uint |
function | ||
true |
literal | ||
try! |
function | ||
tuple |
operator | ||
tx-sender |
keyword | ||
uint |
literal | ||
unwrap! |
function | ||
unwrap-err! |
function | ||
unwrap-err-panic |
function | ||
unwrap-panic |
function | ||
use-trait |
operator | Not implemented yet. | |
var-get |
operator | ||
var-set |
operator | ||
xor |
function |
Legend: