Skip to content
/ sworn Public

Sworn compiles Clarity smart contracts into SmartWeave contracts.

License

Notifications You must be signed in to change notification settings

weavery/sworn

Repository files navigation

Sworn

Project license Discord

Sworn compiles Clarity smart contracts into SmartWeave contracts that run on the Arweave blockchain.

More specifically, the Sworn compiler, called sworn, parses .clar files and compiles them into an equivalent SmartWeave program in the form of JavaScript code.

Sworn also includes experimental WebAssembly contract generation, but we recommend JavaScript output since the generated JS contracts are perfectly human readable and thus feasible to audit.

Screencast

Installation

Binary Downloads

The latest release binaries for macOS and Linux are available here:

To install, after downloading untar the archive and copy the binary to /usr/local/bin, as follows:

macOS

wget https://github.com/weavery/sworn/releases/download/1.0.0/sworn-1.0.0-macos.tar.gz

tar xf sworn-1.0.0-macos.tar.gz

sudo install sworn-1.0.0-macos /usr/local/bin/sworn

Linux

wget https://github.com/weavery/sworn/releases/download/1.0.0/sworn-1.0.0-linux.tar.gz

tar xf sworn-1.0.0-linux.tar.gz

sudo install sworn-1.0.0-linux /usr/local/bin/sworn

Source Code

If you wish to try out the latest and greatest Sworn, 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 Sworn's built-in man page that documents all command-line options, run:

sworn --help

Manpage

Compiling for SmartWeave

To compile the Clarity counter.clar example contract, run:

sworn -t js counter.clar

The previous writes out the JavaScript program to standard output, which is helpful during development and debugging.

However, you can alternatively specify an output file name in the usual way, with the target type inferred from the output file extension:

sworn -o counter.js counter.clar

Compiling to WebAssembly

There is preliminary and experimental support for compiling to WebAssembly. Both the textual representation (.wat) and binary bytecode (.wasm) format are supported as targets:

sworn -t wat counter.clar

sworn -o counter.wasm counter.clar

Note that SmartWeave itself has no WebAssembly interface as yet, so for now you're certainly better off sticking with the JavaScript output. Additionally, JavaScript contracts are human readable and thus auditable.

Examples

Counter Example

(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))))
sworn -t js counter.clar
clarity.requireVersion("0.1")

function getCounter(state) {
  return clarity.ok(state.counter);
}

function increment(state) {
  state.counter = clarity.add(state.counter, 1);
  return {state, result: clarity.ok(state.counter)};
}

function decrement(state) {
  state.counter = clarity.sub(state.counter, 1);
  return {state, result: clarity.ok(state.counter)};
}

export function handle(state, action) {
  const input = action.input;
  if (input.function === 'getCounter') {
    return {result: getCounter(state)};
  }
  if (input.function === 'increment') {
    return increment(state);
  }
  if (input.function === 'decrement') {
    return decrement(state);
  }
  return {state};
}

Notes

Notes on the JavaScript target

The generated SmartWeave code requires Clarity.js, which implements the necessary runtime support for Clarity's standard library.

The generated SmartWeave code may make use of JavaScript's BigInt feature to represent 128-bit integers. All modern browsers support this. On the server side, Node.js 10.4+ supports BigInt.

Mapping of Clarity types

Clarity TypeScript JavaScript Notes
bool boolean boolean
(buff N) Uint8Array Uint8Array
err Err<T> Err
int number or bigint number or BigInt
(list N T) Array<T> Array
(optional T) T or null T or null
principal String String
(response T E) T or Err<E> T or Err
(string-ascii N) String String
(string-utf8 N) String String
(tuple ...) Map<String, any> Map
uint number or bigint number or BigInt

Frequently Asked Questions

Q: Why do arithmetic operations call Clarity.js functions?

In order to support Clarity's language semantics of 128-bit integers and safe arithmetic that traps on numeric overflow and underflow, arithmetic operations need runtime support. Thus, in the general case, an operation such as (* a b) must be compiled to clarity.mul(a, b) instead of the trivial but ultimately incorrect a * b.

Design

Sworn is written in OCaml, an excellent programming language for crafting compiler toolchains.

Sworn is a standard multi-pass compiler consisting of the following stages:

Flowchart

The Clarity parser and abstract syntax tree (AST) originally developed for Sworn have been spun off into a standalone project and OCaml library called Clarity.ml. This 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.

Intermediate representation

Sworn converts Clarity code into an intermediate representation (IR) called SWIR, standing for SmartWeave Intermediate Representation. (See SWIR/grammar.ml for the structure of SWIR.)

Currently, SWIR is very similar to the Clarity AST. However, the Clarity to SWIR conversion stage is nonetheless needed for several reasons:

  1. The Clarity language doesn't yet have a stable specification, and it's easier to keep up with language changes upstream if they only require changes to the compiler frontend instead of throughout the compiler.

  2. SWIR facilitates essential optimizations, such as avoiding unnecessary code generation of relatively expensive 128-bit arithmetic operations in cases where the compiler can prove that 64-bit arithmetic will be safe.

  3. SWIR facilitates code generation for multiple targets such as JavaScript and WebAssembly.

  4. Sworn will in the future endeavor to support other input languages beyond Clarity, which will in any case necessitate an IR.

Code generation

SWIR is converted into either JavaScript or WebAssembly's AST, which can be serialized in binary or text formats.

The JavaScript generation is implemented using OCaml's powerful standard pretty-printing facility, which means that the resulting code is perfectly human readable as well as nicely formatted. (File bug reports if you should find this to not be the case.)

The WebAssembly generation is implemented using the WebAssembly reference implementation, also written in OCaml. This means that Sworn's WebAssembly output is always up-to-date with regards to any changes and features in the latest WebAssembly standard, as well as (by definition) 100% compliant.

Development

This section documents how to get set up with a development environment for building Sworn from source code. It is only of interest to people who wish to contribute to Sworn.

Prerequisites

The following baseline tooling is required in order to build Sworn 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 Sworn from source code:

These aforementioned dependencies are all best installed via OPAM:

opam install -y alcotest cmdliner cppo iso8601 num ocolor wasm
opam pin add -y clarity-lang https://github.com/weavery/clarity.ml -k git

Running the program

alias sworn='dune exec bin/sworn/sworn.exe --'

sworn --help

Installing from source code

git clone https://github.com/weavery/sworn.git

cd sworn

dune build

sudo install _build/default/bin/sworn/sworn.exe /usr/local/bin/sworn

Acknowledgments

We thank Arweave and Blockstack for sponsoring the development of Sworn.

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 JavaScript WebAssembly Notes
* function
+ function
- function
/ function
< function 🚧
<= function 🚧
> function 🚧
>= function 🚧
and syntax 🚧
append function 🚧
as-contract syntax 🚧
as-max-len? syntax 🚧
asserts! syntax 🚧
at-block syntax Not supported by SmartWeave.
begin syntax
block-height keyword 🚧
bool type
buff type 🚧
concat function 🚧
contract-call? function Not supported by SmartWeave.
contract-caller keyword 🚧
contract-of function Not supported by SmartWeave.
default-to function 🚧
define-constant syntax
define-data-var syntax
define-fungible-token syntax 🚧 🚧
define-map syntax 🚧
define-non-fungible-token syntax 🚧 🚧
define-private syntax
define-public syntax
define-read-only syntax
define-trait syntax Not supported by SmartWeave.
err function 🚧
false constant
filter function 🚧
fold function 🚧
ft-get-balance function 🚧
ft-mint? function 🚧
ft-transfer? function 🚧
get syntax 🚧
get-block-info? function Not supported by SmartWeave.
hash160 function 🚧
if syntax 🚧
impl-trait syntax Not supported by SmartWeave.
int type
is-eq function 🚧
is-err function 🚧
is-none function 🚧
is-ok function 🚧
is-some function 🚧
keccak256 function 🚧
len function 🚧
let syntax 🚧
list type 🚧
list function 🚧
map function 🚧
map-delete function 🚧
map-get? function 🚧
map-insert function 🚧
map-set function 🚧
match syntax 🚧
mod function
nft-get-owner? function 🚧
nft-mint? function 🚧
nft-transfer? function 🚧
none constant 🚧
not function 🚧
ok function
optional type
or syntax 🚧
pow function
principal type 🚧
print function 🚧
response type 🚧
sha256 function 🚧
sha512 function 🚧
sha512/256 function 🚧
some function 🚧
stx-burn? function Not supported by SmartWeave.
stx-get-balance function Not supported by SmartWeave.
stx-transfer? function Not supported by SmartWeave.
to-int function 🚧
to-uint function 🚧
true constant
try! function 🚧
tuple type 🚧
tx-sender keyword 🚧
uint type
unwrap! function 🚧
unwrap-err! function 🚧
unwrap-err-panic function 🚧
unwrap-panic function 🚧
use-trait syntax Not supported by SmartWeave.
var-get function
var-set function
xor function 🚧

Legend: ❌ = not supported. 🚧 = work in progress. ✅ = supported.