[extensions] ethereum call decode params
Signed-off-by: Andrey Shovkoplyas <motor4ik@gmail.com>
This commit is contained in:
parent
3eda5e3bfc
commit
f8ef431373
|
@ -264,6 +264,7 @@
|
|||
:arguments {:to :string
|
||||
:method :string
|
||||
:params? :vector
|
||||
:outputs? :vector
|
||||
:on-result? :event}}}
|
||||
:hooks {:commands commands/command-hook}})
|
||||
|
||||
|
|
|
@ -4,7 +4,8 @@
|
|||
[status-im.models.wallet :as models.wallet]
|
||||
[status-im.utils.ethereum.abi-spec :as abi-spec]
|
||||
[status-im.utils.fx :as fx]
|
||||
[status-im.ui.screens.navigation :as navigation]))
|
||||
[status-im.ui.screens.navigation :as navigation]
|
||||
[clojure.string :as string]))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:extensions/transaction-on-result
|
||||
|
@ -29,11 +30,15 @@
|
|||
|
||||
(handlers/register-handler-fx
|
||||
:extensions/ethereum-call
|
||||
(fn [_ [_ {:keys [to method params on-result]}]]
|
||||
(fn [_ [_ {:keys [to method params outputs on-result]}]]
|
||||
(let [tx-object {:to to :data (when method (abi-spec/encode method params))}]
|
||||
{:browser/call-rpc [{"jsonrpc" "2.0"
|
||||
"method" "eth_call"
|
||||
"params" [tx-object "latest"]}
|
||||
#(when on-result
|
||||
(re-frame/dispatch (on-result {:error %1 :result (when %2
|
||||
(get (js->clj %2) "result"))})))]})))
|
||||
(let [result-str (when %2
|
||||
(get (js->clj %2) "result"))
|
||||
result (if (and outputs result-str)
|
||||
(abi-spec/decode (string/replace result-str #"0x" "") outputs)
|
||||
result-str)]
|
||||
(re-frame/dispatch (on-result {:error %1 :result result}))))]})))
|
|
@ -1,7 +1,8 @@
|
|||
(ns status-im.utils.ethereum.abi-spec
|
||||
(:require [cljs.spec.alpha :as spec]
|
||||
[clojure.string :as string]
|
||||
[status-im.js-dependencies :as dependencies]))
|
||||
[status-im.js-dependencies :as dependencies]
|
||||
[clojure.string :as str]))
|
||||
|
||||
;; Utility functions for encoding
|
||||
|
||||
|
@ -33,6 +34,12 @@
|
|||
(defn number-to-hex [x]
|
||||
(subs (.numberToHex utils x) 2))
|
||||
|
||||
(defn hex-to-utf8 [x]
|
||||
(.hexToUtf8 utils (str "0x" x)))
|
||||
|
||||
(defn hex-to-number [x]
|
||||
(.hexToNumber utils (str "0x" x)))
|
||||
|
||||
(defn sha3 [s]
|
||||
(.sha3 utils (str s)))
|
||||
|
||||
|
@ -267,3 +274,116 @@
|
|||
params)]
|
||||
(str method-id (enc {:type :tuple
|
||||
:value params})))))
|
||||
|
||||
;; ======= decode
|
||||
|
||||
(defn substr [val s l]
|
||||
(subs val s (+ s l)))
|
||||
|
||||
;; "[]" -> 0 , "[1]" -> 1
|
||||
(defn arr-size [val]
|
||||
(int (apply str (rest (butlast val)))))
|
||||
|
||||
;; [2] -> 2 , [1] -> 1 , [] - > 1
|
||||
(defn nested-size [val]
|
||||
(let [num (arr-size val)]
|
||||
(if (zero? num) 1 num)))
|
||||
|
||||
;; '("[1]" "[]") or nil
|
||||
(defn list-of-nested-types [type]
|
||||
(when-let [res (re-seq #"(\[[0-9]*\])" type)]
|
||||
(map first res)))
|
||||
|
||||
(defn nested-name [type]
|
||||
(let [ntypes (list-of-nested-types type)]
|
||||
(if ntypes
|
||||
(subs type 0 (- (count type) (count (last ntypes))))
|
||||
type)))
|
||||
|
||||
(defn is-arr? [type]
|
||||
(boolean (list-of-nested-types type)))
|
||||
|
||||
(defn is-dynamic-arr? [type]
|
||||
(let [ntypes (list-of-nested-types type)]
|
||||
(and ntypes (zero? (arr-size (last ntypes))))))
|
||||
|
||||
(defn static-arr-len [type]
|
||||
(let [ntypes (list-of-nested-types type)]
|
||||
(if ntypes
|
||||
(nested-size (last ntypes))
|
||||
1)))
|
||||
|
||||
(defn static-part-length [type]
|
||||
(apply * (conj (map nested-size (or (list-of-nested-types type) '("1"))) 32)))
|
||||
|
||||
(defn offset-reducer [{:keys [cnt coll]} val]
|
||||
(let [cnt' (+ cnt val)]
|
||||
{:cnt cnt'
|
||||
:coll (conj coll cnt')}))
|
||||
|
||||
(defn get-offsets [types]
|
||||
(let [lengths (map static-part-length types)]
|
||||
(conj (butlast (:coll (reduce offset-reducer {:cnt 0 :coll []} lengths))) 0)))
|
||||
|
||||
(defn hex-to-bytes [hex]
|
||||
(let [len (* (.toNumber (.toBN utils (subs hex 0 64))) 2)]
|
||||
(substr hex 64 len)))
|
||||
|
||||
(defn dyn-hex-to-value [hex type]
|
||||
(cond
|
||||
(str/starts-with? type "bytes")
|
||||
(str "0x" (hex-to-bytes hex))
|
||||
|
||||
(str/starts-with? type "string")
|
||||
(hex-to-utf8 (hex-to-bytes hex))))
|
||||
|
||||
(defn hex-to-bytesM [hex type]
|
||||
(let [size (int (second (re-matches #"^bytes([0-9]*)" type)))]
|
||||
(subs hex 0 (* 2 size))))
|
||||
|
||||
(defn hex-to-value [hex type]
|
||||
(cond
|
||||
(= "bool" type) (= hex "0000000000000000000000000000000000000000000000000000000000000001")
|
||||
(str/starts-with? type "uint") (hex-to-number hex)
|
||||
(str/starts-with? type "int") (hex-to-number hex)
|
||||
(str/starts-with? type "address") (str "0x" (subs hex (- (count hex) 40)))
|
||||
(str/starts-with? type "bytes") (hex-to-bytesM hex type)))
|
||||
|
||||
(defn dec-type [bytes]
|
||||
(fn [offset type]
|
||||
(cond
|
||||
(is-arr? type)
|
||||
|
||||
(let [dyn-arr? (is-dynamic-arr? type)
|
||||
arr-off (js/parseInt (str "0x" (substr bytes (* offset 2) 64)))
|
||||
len (if dyn-arr?
|
||||
(js/parseInt (str "0x" (substr bytes (* arr-off 2) 64)))
|
||||
(static-arr-len type))
|
||||
arr-start (if dyn-arr? (+ arr-off 32) offset)
|
||||
|
||||
nname (nested-name type)
|
||||
nstatpartlen (static-part-length nname)
|
||||
rnstatpartlen (* (js/Math.floor (/ (+ nstatpartlen 31) 32)) 32)]
|
||||
(loop [res [] i 0]
|
||||
(if (>= i (* len rnstatpartlen))
|
||||
res
|
||||
(recur (conj res ((dec-type bytes) (+ arr-start i) nname)) (+ i rnstatpartlen)))))
|
||||
|
||||
(or (re-matches #"^bytes(\[([0-9]*)\])*$" type)
|
||||
(str/starts-with? type "string"))
|
||||
|
||||
(let [dyn-off (js/parseInt (str "0x" (substr bytes (* offset 2) 64)))
|
||||
len (js/parseInt (str "0x" (substr bytes (* dyn-off 2) 64)))
|
||||
rlen (js/Math.floor (/ (+ len 31) 32))
|
||||
val (substr bytes (* dyn-off 2) (* (+ rlen 1) 64))]
|
||||
(dyn-hex-to-value val type))
|
||||
|
||||
:else
|
||||
|
||||
(let [len (static-part-length type)
|
||||
val (substr bytes (* offset 2) (* len 2))]
|
||||
(hex-to-value val type)))))
|
||||
|
||||
(defn decode [bytes types]
|
||||
(let [offsets (get-offsets types)]
|
||||
(map (dec-type bytes) offsets types)))
|
|
@ -17,3 +17,29 @@
|
|||
|
||||
(is (= (abi-spec/encode "g(uint[][],string[])" [[[1 2] [3]] ["one" "two" "three"]])
|
||||
"0xad6a3446000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000036f6e650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000374776f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000057468726565000000000000000000000000000000000000000000000000000000")))
|
||||
|
||||
(deftest test-decode
|
||||
(is (= (abi-spec/decode "000000000000000000000000000000000000000000000000000000005bc741cd00000000000000000000000000000000000000000000000000000000000000a000000000000000000000000013b86dbf1a83c9e6a492914a0ee39e8a5b7eb60700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002e516d533152484e4a57414b356e426f6f57454d34654d644268707a35666e325764557473457357754a4b79356147000000000000000000000000000000000000"
|
||||
["uint256" "bytes" "address" "uint256" "uint256"])
|
||||
'(1539785165
|
||||
"0x516d533152484e4a57414b356e426f6f57454d34654d644268707a35666e325764557473457357754a4b79356147"
|
||||
"0x13b86dbf1a83c9e6a492914a0ee39e8a5b7eb607"
|
||||
0
|
||||
0)))
|
||||
|
||||
(is (= (abi-spec/decode "00000000000000000000000000000000000000000000000000000000000000450000000000000000000000000000000000000000000000000000000000000001"
|
||||
["uint32" "bool"])
|
||||
'(69 true)))
|
||||
|
||||
(is (= (map abi-spec/hex-to-utf8
|
||||
(first (abi-spec/decode "61626300000000000000000000000000000000000000000000000000000000006465660000000000000000000000000000000000000000000000000000000000"
|
||||
["bytes3[2]"])))
|
||||
'("abc" "def")))
|
||||
|
||||
(is (= (abi-spec/decode "0000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000464617665000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003"
|
||||
["string" "bool" "uint256[]"])
|
||||
'("dave" true [1 2 3])))
|
||||
|
||||
(is (= (abi-spec/decode "00000000000000000000000000000000000000000000000000000000000001230000000000000000000000000000000000000000000000000000000000000080313233343536373839300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000004560000000000000000000000000000000000000000000000000000000000000789000000000000000000000000000000000000000000000000000000000000000d48656c6c6f2c20776f726c642100000000000000000000000000000000000000"
|
||||
["uint" "uint32[]" "bytes10" "bytes"])
|
||||
'(291 [1110 1929] "31323334353637383930" "0x48656c6c6f2c20776f726c6421"))))
|
Loading…
Reference in New Issue