Skip to content

Commit

Permalink
Merge pull request #3 from pelle/contract-improvements
Browse files Browse the repository at this point in the history
Contract improvements
  • Loading branch information
pelle authored Aug 29, 2016
2 parents b0bf5f3 + 3e36823 commit 1816f16
Show file tree
Hide file tree
Showing 6 changed files with 68 additions and 13 deletions.
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# CLOTH Changelog

### 0.2.7

- Fix `bytes` and `bytesXX` encoding and decoding of solidity function call parameters
- Accepts "0x" prefixed hex string which gets decoded and converted to bytearray/Buffer
- Any other strings are converted to bytearray or Buffer
- bytearray/Buffers are directly accepted
- decoding always returns a bytearray or Buffer depending on Clojure or ClojureScript
- Added Clojure Docs for all functions generated from Solidity. This can be improved but it's better than nothing.
- More robust solidity compilation process
- Now correctly picks the solidity contract when compiling based on multiple sourcefile dependencies in `(defcontract)`
- Correctly means means that it assumes the Solidity contract is the Capitalized camelized name of the contract name passed into `(defcontract name path)`
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ This is extremely WIP and really should not be used by anyone yet. API is likely

Add the following to your project.clj file:

`[cloth "0.2.5"]`
`[cloth "0.2.7"]`

Note I have not tested any of this in production or using minified clojurescript code.

Expand Down
7 changes: 4 additions & 3 deletions project.clj
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
(defproject cloth "0.2.6"
(defproject cloth "0.2.7"
:description "Clojure(Script) tools for Ethereum"
:url "https://github.com/pelle/cloth"
:dependencies [[org.clojure/clojure "1.9.0-alpha8"]
[org.clojure/clojurescript "1.9.93"]
[org.clojure/clojurescript "1.9.225"]
[org.clojure/core.async "0.2.385"]
[funcool/cats "2.0.0"]
[funcool/promesa "1.4.0"]
[funcool/promesa "1.5.0"]
[funcool/httpurr "0.6.1"]
[aleph "0.4.1" :scope "provided"]
[funcool/cuerdas "0.8.0"]
[org.ethereum/ethereumj-core "1.2.0-RELEASE"]
[clj-time "0.12.0"]
[com.andrewmcveigh/cljs-time "0.4.0"]
;[cljsjs/bignumber "2.1.4-1"]

[cheshire "5.6.3"]]
:jvm-opts ^:replace ["-Xmx1g" "-server"]
:plugins [[lein-npm "0.6.1"]
Expand Down
26 changes: 24 additions & 2 deletions src/cloth/contracts.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@

#?(:clj
(defn compile-solidity [file]
(json/parse-string (:out (shell/sh "solc" "--combined-json" "abi,bin" file)) true)))
(let [result (shell/sh "solc" "--combined-json" "abi,bin" file)]
(if (not (c/blank? (:err result)))
(throw (ex-info (:err result) {:solidity file :exit (:exit result)}))
(json/parse-string (:out result) true)))))

#?(:clj
(defn abi->args [f]
Expand Down Expand Up @@ -58,6 +61,14 @@
:topics [(util/encode-event-sig (:name fn-abi) (map :type (:inputs fn-abi)))]
:parser parser})))

(defn fn-doc [ fn-abi]
(let [fncall (str (:name fn-abi) "(" (c/join ", " (map #(str (:type %) " " (:name % (:type %))) (:inputs fn-abi))) ")")
const (if (:constant fn-abi) " constant")
returns (if (not (empty? (:outputs fn-abi)))
(str " returns(" (c/join ", " (map #(str (:type %) (if (:name %) (str " " (:name %)))) (:outputs fn-abi))) ")"))
]
(str fncall const returns)))

;; (<function name>!)
#?(:clj
(defmacro defcontract
Expand All @@ -74,7 +85,7 @@
"
[contract file]
(let [compiled (compile-solidity file)
contract-key (first (keys (:contracts compiled))) ;(c/capitalize (c/camelize (name contract)))
contract-key (keyword (c/capitalize (c/camelize (name contract))))
binary (get-in compiled [:contracts contract-key :bin])
abi (json/parse-string (get-in compiled [:contracts contract-key :abi]) true)
functions (filter #(= (:type %) "function") abi)
Expand All @@ -87,22 +98,33 @@
~@(for [f functions]
(if (:constant f)
`(defn ~(symbol (c/dasherize (:name f)))
~(str
"Calls "
(fn-doc f)
" without creating a transaction\nReturns a promise will return function return value")
[contract# & args#]
(call-contract-fn ~f contract# args#))
`(do
(defn ~(symbol (str (c/dasherize (:name f)) "!"))
~(str "Calls " (fn-doc f) " and submit it as a transaction\nReturns a promise which will return the tx hash")
[contract# & args#]
(create-fn-tx ~f contract# args#))
(defn ~(symbol (str (c/dasherize (:name f)) "!!"))
~(str "Calls " (fn-doc f) " and submit it as a transaction.\nReturns a promise which will return the tx receipt once it has mined")
[contract# & args#]
(create-fn-and-wait-for-receipt ~f contract# args#))
(defn ~(symbol (str (c/dasherize (:name f)) "?"))
~(str "Calls " (fn-doc f) " without creating a transaction. Returns a promise which will return function return value")
[contract# & args#]
(call-contract-fn ~f contract# args#)))))

~@(for [e events]
(do
`(defn ~(symbol (str (c/dasherize (:name e)) "-ch"))
~(str
"Listen to event "
(fn-doc e)
"\nReturns a promise will return a map containing:\n :events a core.async channel\n :stop a function that stops listening to event.")
[contract# & args#]
(contract-event ~e contract# args#))))

Expand Down
18 changes: 11 additions & 7 deletions src/cloth/util.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -81,11 +81,14 @@
(defn hex0x [buffer]
(add0x (->hex buffer)))

#?(:clj
(defn ->b [b]
(if (string? b)
(.getBytes b)
b)))
(defn ->b [val]
(if (string? val)
(if (re-find #"^0x([0-9a-f]*)$" val)
(hex-> val)
#?(:clj (.getBytes val)
:cljs (Buffer. val)))
val))


(defn sha3 [data]
#?(:cljs
Expand Down Expand Up @@ -116,6 +119,7 @@
[from nonce]
((aget eth-util "generateAddress") from nonce)))


(defn zeros
"Returns a buffer or byte-array filled with 0s"
[length]
Expand Down Expand Up @@ -377,14 +381,14 @@
(defmethod encode-solidity :bytes
[type val]
#?(:cljs
(let [buffer (Buffer. val)]
(let [buffer (->b val)]
(if-let [size (extract-size type)]
(->hex (rpad buffer size))
(let [size (.-length buffer)]
(str (solidity-uint 256 size)
(->hex (rpad buffer (storage-length size))))))))
#?(:clj
(let [buffer (.getBytes val)]
(let [buffer (->b val)]
(if-let [size (extract-size type)]
(->hex (rpad buffer size))
(let [size (count buffer)]
Expand Down
15 changes: 15 additions & 0 deletions test/cloth/util_test.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,15 @@
(is (= (util/encode-solidity :int32 -1) "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"))
(is (= (util/encode-solidity :int32 -16772216) "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001388"))


(is (= (util/encode-solidity :bytes32 "0x0000000000000000000000000000000000000000000000000000000000000001") "0000000000000000000000000000000000000000000000000000000000000001"))
(is (= (util/encode-solidity :bytes32 "Hello") "48656c6c6f000000000000000000000000000000000000000000000000000000"))
(is (= (util/encode-solidity :bytes32 (util/hex-> "0x0000000000000000000000000000000000000000000000000000000000000001")) "0000000000000000000000000000000000000000000000000000000000000001"))

(is (= (util/encode-solidity :bytes "0x0000000000000000000000000000000000000000000000000000000000000001") "00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000001"))
(is (= (util/encode-solidity :bytes "Hello") "000000000000000000000000000000000000000000000000000000000000000548656c6c6f000000000000000000000000000000000000000000000000000000"))
(is (= (util/encode-solidity :bytes (util/hex-> "0x0000000000000000000000000000000000000000000000000000000000000001")) "00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000001"))

(is (= (util/encode-solidity :string "hello") "000000000000000000000000000000000000000000000000000000000000000568656c6c6f000000000000000000000000000000000000000000000000000000"))
(is (= (util/encode-solidity :string " ") "00000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000"))
)
Expand Down Expand Up @@ -103,6 +112,12 @@
(is (eq (util/decode-solidity :int32 "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff") -1))
(is (eq (util/decode-solidity :int32 "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001388") -16772216))

(is (= (util/->hex (util/decode-solidity :bytes32 "0000000000000000000000000000000000000000000000000000000000000001")) "0000000000000000000000000000000000000000000000000000000000000001"))
(is (= (util/->hex (util/decode-solidity :bytes32 "48656c6c6f000000000000000000000000000000000000000000000000000000")) "48656c6c6f000000000000000000000000000000000000000000000000000000"))

(is (= (util/->hex (util/decode-solidity :bytes "00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000001")) "0000000000000000000000000000000000000000000000000000000000000001"))
(is (= (util/->hex (util/decode-solidity :bytes "000000000000000000000000000000000000000000000000000000000000000548656c6c6f000000000000000000000000000000000000000000000000000000")) "48656c6c6f"))

(is (= (util/decode-solidity :string "000000000000000000000000000000000000000000000000000000000000000568656c6c6f000000000000000000000000000000000000000000000000000000")
"hello"))
(is (= (util/decode-solidity :string "00000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000") " " ))
Expand Down

0 comments on commit 1816f16

Please sign in to comment.