A chialisp library to develop smart coins (contracts) on the Chia Blockchain by Hashgreen Labs.
- Implements standards like Chia Asset Token (CAT) and singleton.
- Object-oriented-like interface for easier development.
- Reusable components for building complex contracts.
Make sure you have Poetry first, then run:
$ git clone https://github.com/hashgreen/cypher.git && cd cypher
$ poetry shell && poetry install
Cypher is planned to be released as a package under PyPI once it reaches a stable version.
$ run --include . tests/test-hello-world.clsp
If dependencies are installed correctly, you should see "hello-world passed"
.
Once installed, you can use Cypher in a chialisp contract by importing them with include
.
The main Cypher library is imported via cypher.clsp
, and the re-implemented Chia standards can be imported separately from chia/*.clsp
.
(mod () ; add variables here
(include cypher.clsp)
(include chia/cat-lib.clsp)
(defun main
() ; begin to write your main logic here about your cool CAT
)
(main)
)
You can find a list of exported symbols at the end of each file. They look like:
;; Exports
(defmacro ... args (c ... args))
We have included tests for the library, written in chialisp as well under tests/
.
To run the test suite, simply run
$ make -j8 test
Check out our reimplementation of standard puzzles to understand better how you can use Cypher to achieve your goals.
The goals of Cypher are to achieve:
-
Boilerplate Reduction
In many official implementations such as Chia Asset Token, we see countless utility functions copied and pasted over and over. By importing these utilities from Cypher, the chialisp community can reduce the excessive copy-and-pasting, significantly increase the readability in their implementation, and only focus on the critical logic of their smart coins.
-
Security
As we all know, we learn smart contract security by avoiding others' mistakes, and the official standards are no exception. We aim to incorporate logical checks around some commonly used functions, and ensure the invoked usages do not fall for basic exploits. If you feel brave and completely understand what you are operating, you will have to explicitly opt out by using unsafe variations of the functions to remove these security checks.
-
Common Utilities
It is annoying to do complex math, especially if you are writing a functional language. We incorporated an array of mathematical utilities ranging from fractional math to logarithms, to make decentralized finance easier. There are also condition-related, macro-related utilities waiting to be explored!
-
Implementation of Standards
Learning from the official standards can be a great way to pick up chialisp knowledge, and we refactor the official implementation into chialisp scripts that uses Cypher and are much more reader-friendly.
You will have a lot of questions to ask about the design of Cypher. We do not promise we have answers to all, and yet we strive hard to follow the conventions of the Lisp language and balance it in the context of chialisp.
-
Choice of Namespace
If you dive deep enough, you will discover variables exported with different prefixes: no prefix,
cf.
-prefixed,@cf.
-prefixed, and%cf.
-prefixed, with the goal of reminding the user the underlying implementation. For example, it has been a practice to directly invoke clvm condition codes such asAGG_SIG_ME
orCREATE_COIN
with the bare names directly. Other constants are less standardized and putting them under thecf.
namespace sounds more reasonable.As for
@cf.
exports like@cf.and
, we highlight the fact that they are secretly macros which focus on modifying the bodies of parameters they are passed in.In the library, there are some other more complex functions (e.g.,
cf.log
) that tries to use the argument multiple times, and passing arguments in a inline style would make the compiled program a literal hell as the arguments will be expanded everywhere. For these functions the default is to usedefun
to wrap around the arguments, and you can opt out and usedefun-inline
by doing%cf.log
if you know what you are doing. -
Object-Oriented-Like
Lisp is an elegant functional language that has existed for decades. Why make it OOP -- you might ask. This generation of programmers are just too spoiled by object-oriented programming that they cannot simply awe the beauty of Lisp, or its descendant, chialisp. Hence OOP we must... We must...
-
.clsp
,.clvm
, or.clib
?There is a long debate how one should name a chialisp implementation file, or a compiled chialisp script, or even a hex file. Across the board, there are who love
.clvm
extensions and who love.clsp
extensions. That said, we decided to name chialisp implementations.clsp
, compiled low-level language.clvm
, and hex-serialized bytecode.clvm.hex
. We will not include a commonly used extensionclib
, as everything we write are honestly library code, and it would look very much like we are writing library for C language for someone who does not have a sufficient context.
There is a pretty significant caveat of using Cypher -- the compile time for your chialisp program may be excruciatingly long!
This is because in the implementation of the official compiler reads all symbols and consider all of them in each step of the optimization.
Importing Cypher by (import cypher.clsp)
would trigger this by introducing all symbols into your program.
For example, compiling the refactored singleton v1.1 took ~70s on a reasonably well machine.
$ run --include . chia/singleton-v1-1.clsp > chia/singleton-v1-1.clvm
There are three options to go
- You an either directly import the desired second-level library by
(import cypher/math.clsp)
, or - You can wait until this new compiler to mature, and hopefully compiles everything blazingly fast!
- Or... you can pull out pypy magic! See the section below.
Importing the full symbol soup from Cypher is known to introduce long compilation time due to the lack of optimization in the vanilla chialisp compiler. Specifically, as detailed in a comparison sheet, the python-based compiler can take up to 11 minutes on a decent linux workstation, while the polished rust-based compiler port can still take up to a minute.
To alleviate the problem, we have improved the vanilla compiler, and switched to pypy as the python interpreter for compilation, the two of which combined give a performance boost of > 50x.
To run compilation in pypy, make sure Anaconda is installed first, then enable pypy mode
$ conda env create -f environment.yml -n pypy
$ PYPY_MODE=1 make clean compile
Be a contributor by opening up an issue or pull request!
Cypher is released under Apache 2.0.