Many blockchain-related services use uint256 math meanwhile Clarity only supports uint up to 128-bits long. Initially, my idea was to build the library for elliptic curve operations on finite fields that can be used by some other algorithms but it appeared to be pointless without uint256 as for security reasons the large field parameters are used.
What it does
The library implements common operations on numbers. There are two approaches of its usage represented by
The code is also covered by automated tests.
How I built it
Challenges I ran into
Working with Clarity I felt the need of some syntactic sugar, standards and improvements that would make code more readable and deployment process more comfortable:
- Type declaration in order to clearly see the same types. For instance:
(type point (tuple (i0 u0) (i1 u0) (i2 u0) (i3 u0)))
- Imports to avoid copying common code. For instance:
Clarify logs. Now it displays only part of the call stack(the top-level function only).
Fix or documement recursive calls error, generated by composition of the same function. To reproduce error, replace
contracts/uint256-ecc-libby this one:
(define-public (ecc-add (p1 (tuple (x (tuple (i0 uint) (i1 uint) (i2 uint) (i3 uint))) (y (tuple (i0 uint) (i1 uint) (i2 uint) (i3 uint))))) (p2 (tuple (x (tuple (i0 uint) (i1 uint) (i2 uint) (i3 uint))) (y (tuple (i0 uint) (i1 uint) (i2 uint) (i3 uint)))))) (if (is-zero-point p1) (ok p2) (if (is-zero-point p2) (ok p1) (if (and (uint256-is-eq (get x p1) (get x p2)) (uint256-is-eq (get y p1) (get y p2))) (if (uint256-is-zero (get y p1)) (ok (tuple (x uint256-zero) (y uint256-zero))) (let ((m (uint256-div (uint256-mul-mod-short (uint256-mul-mod (get x p1) (get x p1) zk-p) u3 zk-p) (uint256-mul-mod-short (get y p1) u2 zk-p)))) (let ((m1 (uint256-mul-mod m m zk-p)) (m2 (uint256-mul-mod-short (get x p1) u2 zk-p))) (let ((x (uint256-sub m1 m2))) (ok (tuple (x x) (y (uint256-sub (uint256-mul-mod m (uint256-sub (get x p1) x) zk-p) (get y p1))))))))) ;; << CHANGES HERE (if (uint256-is-eq (get x p1) (get x p2)) (ok (tuple (x uint256-zero) (y uint256-zero))) (let ((mt (uint256-sub (get x p2) (get x p1)))) (let ((m (uint256-div (uint256-sub (get y p2) (get y p1)) mt))) (let ((xt (uint256-sub (uint256-mul-mod m m zk-p) (get x p1)))) (let ((x (uint256-sub xt (get x p2)))) (let ((yt (uint256-mul-mod m (uint256-sub (get x p1) x) zk-p))) (ok (tuple (x x) (y (uint256-sub yt (get y p1))))))))))) ))))
Code style standart. It's not clear how to indent and wrap code to make readable for others. For instance, Golang has such a utill as
fmtthat solves the issue by formating code and teach everybody write standartized code.
Better docs and tutorials.
Developer-friendly deployment from UI. There is no way to load or save the contract code on the sandbox(editing the samples is the only option).
Expand deployment fail reasons. The message is not really helpful:
This transaction did not succeed because the transaction was aborted during its execution.
Accomplishments that I'm proud of
I can read Lisp-like language and my eyes don't bleed anymore because of thousands of brackets. It was a funny experience.
What I learned
Lisp paradigm, interpreted approach for smart contracts, blockstack ecosystem related to smart contracts deployment, @blockstack/clarity sdk (BTW, awesome stuff, no pain).
What's next for Uint256-lib
It will stay open-source and will be able to serve the community. It also needs more tests. More functions may be implemented. For instance, according to this API.
As for Clarity in general, I am interested in creating some kind of tutorial with code examples as it was slightly painful to navigate in docs and there are a few contract examples. I like the Golang approach where the theory is illustrated by the code snippet that can be run immediately. Actually, clarity.tools can be a good example of the right part of the educational platform where the left side is extended by an explanation. Let me know if you are interested in it.