Skip to content

Commit

Permalink
[refactoring] remove web3, clean up wallet effects
Browse files Browse the repository at this point in the history
- introduce json-rpc namespace, which provides `call` and `eth-call`,
a generic way of calling a json-rpc method taking care of conversions
and error handling
- remove web3 usage from wallet
- clean up effects, reducing the amount of computations when login in
  • Loading branch information
yenda committed May 20, 2019
1 parent e7f0482 commit 18c326f
Show file tree
Hide file tree
Showing 25 changed files with 496 additions and 708 deletions.
5 changes: 3 additions & 2 deletions src/status_im/accounts/login/core.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,10 @@
(fx/defn initialize-wallet [cofx]
(fx/merge cofx
(wallet/initialize-tokens)
(wallet/update-balances)
(wallet/update-prices)
(transactions/initialize)
(ethereum.subscriptions/initialize)
(wallet/update-wallet)))
(ethereum.subscriptions/initialize)))

(fx/defn user-login [{:keys [db] :as cofx} create-database?]
(let [{:keys [address password]} (accounts.db/credentials cofx)]
Expand Down
6 changes: 3 additions & 3 deletions src/status_im/chat/commands/impl/transactions.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -329,9 +329,9 @@
;; TODO(janherich) - refactor wallet send events, updating gas price
;; is generic thing which shouldn't be defined in wallet.send, then
;; we can include the utility helper without running into circ-dep problem
:update-gas-price {:web3 (:web3 db)
:success-event :wallet/update-gas-price-success
:edit? false}}
:wallet/update-gas-price
{:success-event :wallet/update-gas-price-success
:edit? false}}
(navigation/navigate-to-cofx next-view-id {}))))
protocol/EnhancedParameters
(enhance-send-parameters [_ parameters cofx]
Expand Down
61 changes: 61 additions & 0 deletions src/status_im/ethereum/contracts.cljs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
(ns status-im.ethereum.contracts
(:require [re-frame.core :as re-frame]
[status-im.utils.ethereum.abi-spec :as abi-spec]
[status-im.utils.ethereum.core :as ethereum]
[status-im.utils.fx :as fx]
[status-im.utils.money :as money]
[status-im.wallet.core :as wallet]))

(def contracts
{:status/tribute-to-talk
{:address
{:mainnet nil
:testnet "0x3da3fc53e24707f36c5b4433b442e896c4955f0e"
:rinkeby nil}
:methods
{:get-manifest
{:signature "getManifest(address)"
:outputs ["bytes"]}
:set-manifest
{:signature "setManifest(bytes)"
:write? true}}}})

(re-frame/reg-fx
::call
(fn [{:keys [address data callback]}]
(ethereum/call {:to address
:data data}
callback)))

(defn get-contract-address
[db contract]
(let [chain-keyword (-> (get-in db [:account/account :networks (:network db)])
ethereum/network->chain-keyword)]
(get-in contracts [contract :address chain-keyword])))

(fx/defn call
[{:keys [db] :as cofx}
{:keys [contract contract-address method params
callback on-result on-error details]}]
(when-let [contract-address (or contract-address
(get-contract-address db contract))]
(let [{:keys [signature outputs write?]}
(get-in contracts [contract :methods method])
data (abi-spec/encode signature params)]
(if write?
(wallet/open-sign-transaction-flow
cofx
(merge {:to contract-address
:data data
:id "approve"
:symbol :ETH
:method "eth_sendTransaction"
:amount (money/bignumber 0)
:on-result on-result
:on-error on-error}
details))
{::call {:address contract-address
:data data
:callback #(callback (if (empty? outputs)
%
(abi-spec/decode % outputs)))}}))))
74 changes: 74 additions & 0 deletions src/status_im/ethereum/json_rpc.cljs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
(ns status-im.ethereum.json-rpc
(:require [clojure.string :as string]
[re-frame.core :as re-frame]
[status-im.ethereum.decode :as decode]
[status-im.native-module.core :as status]
[status-im.utils.ethereum.abi-spec :as abi-spec]
[status-im.utils.money :as money]
[status-im.utils.types :as types]
[taoensso.timbre :as log]))

(def json-rpc-api
{"eth_call" {}
"eth_getBalance"
{:on-result money/bignumber}
"eth_estimateGas"
{:on-result money/bignumber}
"eth_gasPrice"
{:on-result money/bignumber}
"eth_getBlockByHash"
{:on-result #(-> (update % :number decode/uint)
(update :timestamp decode/uint))}
"eth_getTransactionByHash" {}
"eth_getTransactionReceipt" {}
"eth_newBlockFilter" {:subscription? true}
"eth_newFilter" {:subscription? true}})

(defn call
[{:keys [method params on-success on-error]}]
(when-let [method-options (json-rpc-api method)]
(let [{:keys [id on-result subscription?]
:or {on-result identity
id 1
params []}} method-options
on-error (or on-error
#(log/error :json-rpc/error key :params params :error %))]
(if (nil? method)
(log/error :json-rpc/method-not-found key)
(status/call-private-rpc
(types/clj->json {:jsonrpc "2.0"
:id id
:method (if subscription?
"eth_subscribeSignal"
method)
:params (if subscription?
[method params]
params)})
(fn [response]
(if (string/blank? response)
(on-error {:message "Blank response"})
(let [{:keys [error result] :as response2} (types/json->clj response)]
(if error
(on-error error)
(if subscription?
(re-frame/dispatch
[:ethereum.callback/subscription-success
result on-success])
(on-success (on-result result))))))))))))

(defn eth-call
[{:keys [contract method params outputs on-success on-error block]
:or {block "latest"
params []}}]
(call {:method "eth_call"
:params [{:to contract
:data (abi-spec/encode method params)}
(if (int? block)
(abi-spec/number-to-hex block)
block)]
:on-success
(if outputs
#(on-success (abi-spec/decode % outputs))
on-success)
:on-error
on-error}))
51 changes: 18 additions & 33 deletions src/status_im/ethereum/subscriptions.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
[status-im.utils.ethereum.tokens :as tokens]
[status-im.utils.fx :as fx]
[status-im.utils.types :as types]
[taoensso.timbre :as log]))
[taoensso.timbre :as log]
[status-im.ethereum.json-rpc :as json-rpc]))

(fx/defn handle-signal
[cofx {:keys [subscription_id data] :as event}]
Expand Down Expand Up @@ -56,33 +57,14 @@
;; from etherscan
(transactions/initialize))))))

(defn subscribe-signal
[filter params callback]
(status/call-private-rpc
(types/clj->json {:jsonrpc "2.0"
:id 1
:method "eth_subscribeSignal"
:params [filter params]})
(fn [response]
(if (string/blank? response)
(log/error ::subscription-unknown-error :filter filter :params params)
(let [{:keys [error result]}
(-> (.parse js/JSON response)
(js->clj :keywordize-keys true))]
(if error
(log/error ::subscription-error error :filter filter :params params)
(re-frame/dispatch [:ethereum.callback/subscription-success
result
callback])))))))

(defn new-token-transaction-filter
[{:keys [chain-tokens from to] :as args}]
(subscribe-signal
"eth_newFilter"
[{:fromBlock "latest"
:toBlock "latest"
:topics [constants/event-transfer-hash from to]}]
(transactions/inbound-token-transfer-handler chain-tokens)))
(json-rpc/call
{:method "eth_newFilter"
:params [{:fromBlock "latest"
:toBlock "latest"
:topics [constants/event-transfer-hash from to]}]
:on-success (transactions/inbound-token-transfer-handler chain-tokens)}))

(re-frame/reg-fx
:ethereum.subscriptions/token-transactions
Expand All @@ -95,13 +77,16 @@

(defn new-block-filter
[]
(subscribe-signal
"eth_newBlockFilter" []
(fn [[block-hash]]
(transactions/get-block-by-hash
block-hash
(fn [block]
(re-frame/dispatch [:ethereum.signal/new-block block]))))))
(json-rpc/call
{:method "eth_newBlockFilter"
:on-success
(fn [[block-hash]]
(json-rpc/call
{:method "eth_getBlockByHash"
:params [block-hash true]
:on-success
(fn [block]
(re-frame/dispatch [:ethereum.signal/new-block block]))}))}))

(re-frame/reg-fx
:ethereum.subscriptions/new-block
Expand Down
Loading

0 comments on commit 18c326f

Please sign in to comment.