From ddefae11b13bd802d68492b16da73af338d41639 Mon Sep 17 00:00:00 2001 From: yenda Date: Sat, 24 Aug 2019 02:26:48 +0200 Subject: [PATCH] use wallet_getTokensBalances to reduce number of rpc calls --- src/status_im/ethereum/json_rpc.cljs | 1 + src/status_im/ethereum/transactions/core.cljs | 1 + src/status_im/events.cljs | 35 ----- src/status_im/subs.cljs | 69 ++++---- .../ui/screens/wallet/send/views.cljs | 28 ++-- src/status_im/wallet/core.cljs | 147 ++++++++++++------ 6 files changed, 138 insertions(+), 143 deletions(-) diff --git a/src/status_im/ethereum/json_rpc.cljs b/src/status_im/ethereum/json_rpc.cljs index 6a7a192869..43e2df7f35 100644 --- a/src/status_im/ethereum/json_rpc.cljs +++ b/src/status_im/ethereum/json_rpc.cljs @@ -59,6 +59,7 @@ "status_startOneOnOneChat" {} "status_removeChat" {} "wallet_getTransfers" {} + "wallet_getTokensBalances" {} "browsers_getBrowsers" {} "browsers_addBrowser" {} "browsers_deleteBrowser" {} diff --git a/src/status_im/ethereum/transactions/core.cljs b/src/status_im/ethereum/transactions/core.cljs index bed13b8599..3d75adf22e 100644 --- a/src/status_im/ethereum/transactions/core.cljs +++ b/src/status_im/ethereum/transactions/core.cljs @@ -2,6 +2,7 @@ (:require [re-frame.core :as re-frame] [status-im.constants :as constants] [status-im.ethereum.decode :as decode] + [status-im.ethereum.eip55 :as eip55] [status-im.ethereum.encode :as encode] [status-im.ethereum.json-rpc :as json-rpc] [status-im.ethereum.core :as ethereum] diff --git a/src/status_im/events.cljs b/src/status_im/events.cljs index f800c9fa1c..f37a5d7a45 100644 --- a/src/status_im/events.cljs +++ b/src/status_im/events.cljs @@ -1628,11 +1628,6 @@ (fn [cofx [_ symbol checked?]] (wallet/toggle-visible-token cofx symbol checked?))) -(handlers/register-handler-fx - :wallet/token-found - (fn [cofx [_ address symbol balance]] - (wallet/configure-token-balance-and-visibility cofx address symbol balance))) - (handlers/register-handler-fx :wallet.settings.ui/navigate-back-pressed (fn [cofx [_ on-close]] @@ -1641,36 +1636,6 @@ {:dispatch on-close}) (navigation/navigate-back)))) -(handlers/register-handler-fx - :wallet.callback/update-balance-success - (fn [cofx [_ address balance]] - (wallet/update-balance cofx address balance))) - -(handlers/register-handler-fx - :wallet.callback/update-balance-fail - (fn [cofx [_ err]] - (wallet/on-update-balance-fail cofx err))) - -(handlers/register-handler-fx - :wallet.callback/update-token-balance-success - (fn [cofx [_ address symbol balance]] - (wallet/update-token-balance cofx address symbol balance))) - -(handlers/register-handler-fx - :wallet.callback/update-token-balance-fail - (fn [cofx [_ symbol err]] - (wallet/on-update-token-balance-fail cofx symbol err))) - -(handlers/register-handler-fx - :wallet.callback/update-prices-success - (fn [cofx [_ prices]] - (wallet/on-update-prices-success cofx prices))) - -(handlers/register-handler-fx - :wallet.callback/update-prices-fail - (fn [cofx [_ err]] - (wallet/on-update-prices-fail cofx err))) - (handlers/register-handler-fx :wallet.ui/show-transaction-details (fn [cofx [_ hash address]] diff --git a/src/status_im/subs.cljs b/src/status_im/subs.cljs index 161e0ceddb..cbb391aa54 100644 --- a/src/status_im/subs.cljs +++ b/src/status_im/subs.cljs @@ -354,12 +354,6 @@ (fn [{:keys [public-key]}] public-key)) -(re-frame/reg-sub - :multiaccount/default-address - :<- [:multiaccount] - (fn [{:keys [accounts]}] - (:address (ethereum/get-default-account accounts)))) - (re-frame/reg-sub :sign-in-enabled? :<- [:multiaccounts/login] @@ -1012,7 +1006,7 @@ (re-frame/reg-sub :account-portfolio-value (fn [[_ address] _] - [(re-frame/subscribe [:balance (string/lower-case address)]) + [(re-frame/subscribe [:balance address]) (re-frame/subscribe [:prices]) (re-frame/subscribe [:wallet/currency]) (re-frame/subscribe [:ethereum/chain-keyword]) @@ -1073,7 +1067,7 @@ (re-frame/reg-sub :wallet/visible-assets-with-amount (fn [[_ address] _] - [(re-frame/subscribe [:balance (string/lower-case address)]) + [(re-frame/subscribe [:balance address]) (re-frame/subscribe [:wallet/visible-assets])]) (fn [[balance visible-assets]] (map #(assoc % :amount (get balance (:symbol %))) visible-assets))) @@ -1093,7 +1087,7 @@ (re-frame/reg-sub :wallet/visible-assets-with-values (fn [[_ address] _] - [(re-frame/subscribe [:wallet/visible-assets-with-amount (string/lower-case address)]) + [(re-frame/subscribe [:wallet/visible-assets-with-amount address]) (re-frame/subscribe [:prices]) (re-frame/subscribe [:wallet/currency])]) (fn [[assets prices currency]] @@ -1130,7 +1124,7 @@ (re-frame/reg-sub :wallet/transferrable-assets-with-amount (fn [[_ address]] - (re-frame/subscribe [:wallet/visible-assets-with-amount (string/lower-case address)])) + (re-frame/subscribe [:wallet/visible-assets-with-amount address])) (fn [all-assets] (filter #(not (:nft? %)) all-assets))) @@ -1146,7 +1140,7 @@ :wallet/transactions :<- [:wallet] (fn [wallet [_ address]] - (get-in wallet [:accounts (string/lower-case address) :transactions]))) + (get-in wallet [:accounts address :transactions]))) (re-frame/reg-sub :wallet/filters @@ -1348,38 +1342,6 @@ (fn [send-transaction] (:camera-flashlight send-transaction))) -(defn check-sufficient-funds - [{:keys [sufficient-funds?] :as transaction} balance symbol amount] - (cond-> transaction - (nil? sufficient-funds?) - (assoc :sufficient-funds? - (or (nil? amount) - (money/sufficient-funds? amount (get balance symbol)))))) - -(defn check-sufficient-gas - [transaction balance symbol amount] - (assoc transaction :sufficient-gas? - (or (nil? amount) - (let [available-ether (money/bignumber (get balance :ETH 0)) - available-for-gas (if (= :ETH symbol) - (.minus available-ether (money/bignumber amount)) - available-ether)] - (money/sufficient-funds? (-> transaction - :max-fee - money/bignumber - (money/formatted->internal :ETH 18)) - (money/bignumber available-for-gas)))))) - -(re-frame/reg-sub - :wallet.send/transaction - :<- [::send-transaction] - :<- [:wallet] - (fn [[{:keys [amount symbol from] :as transaction} wallet]] - (let [balance (get-in wallet [:accounts from :balance])] - (-> transaction - (check-sufficient-funds balance symbol amount) - (check-sufficient-gas balance symbol amount))))) - (re-frame/reg-sub :wallet/settings :<- [:wallet] @@ -1903,6 +1865,27 @@ (or amount-error (get-sufficient-gas-error balance (:symbol token) amount-bn gas gasPrice))) (get-sufficient-gas-error balance nil nil gas gasPrice)))) +(re-frame/reg-sub + :wallet.send/transaction + :<- [::send-transaction] + :<- [:wallet] + :<- [:network-status] + :<- [:wallet/all-tokens] + :<- [:ethereum/chain-keyword] + (fn [[{:keys [amount symbol from to amount-error] :as transaction} + wallet network-status all-tokens chain]] + (let [balance (get-in wallet [:accounts from :balance]) + token (tokens/asset-for all-tokens chain symbol)] + (assoc (merge transaction + (when amount + (get-sufficient-funds-error balance symbol amount))) + :balance balance + :token token + :sign-enabled? (and to + (nil? amount-error) + (not (nil? amount)) + (= :online network-status)))))) + ;; NETWORK SETTINGS (defn- filter-networks [network-type] diff --git a/src/status_im/ui/screens/wallet/send/views.cljs b/src/status_im/ui/screens/wallet/send/views.cljs index 8f88479575..80c827cfc9 100644 --- a/src/status_im/ui/screens/wallet/send/views.cljs +++ b/src/status_im/ui/screens/wallet/send/views.cljs @@ -35,10 +35,10 @@ colors/white colors/white-transparent-10)}]]]) -(defn- render-send-transaction-view [{:keys [chain transaction scroll all-tokens amount-input network-status]}] - (let [{:keys [from amount amount-text amount-error asset-error to to-name sufficient-funds? symbol]} transaction - {:keys [decimals] :as token} (tokens/asset-for all-tokens chain symbol) - online? (= :online network-status)] +(defn- render-send-transaction-view + [{:keys [transaction scroll amount-input]}] + (let [{:keys [from amount amount-text amount-error token sign-enabled? + asset-error to to-name symbol]} transaction] [wallet.components/simple-screen {:avoid-keyboard? true :status-bar-type :wallet} [toolbar (i18n/label :t/send-transaction)] @@ -58,16 +58,12 @@ :type :send :symbol symbol}] [wallet.components/amount-selector - {:error (or amount-error (when-not sufficient-funds? (i18n/label :t/wallet-insufficient-funds))) + {:error amount-error :amount amount :amount-text amount-text - :input-options {:on-change-text #(re-frame/dispatch [:wallet.send/set-and-validate-amount % symbol decimals]) + :input-options {:on-change-text #(re-frame/dispatch [:wallet.send/set-and-validate-amount %]) :ref (partial reset! amount-input)}} token]]] - [sign-transaction-button (and to - (nil? amount-error) - (not (nil? amount)) - sufficient-funds? - online?)]]])) + [sign-transaction-button sign-enabled?]]])) (defn- send-transaction-view [{:keys [scroll]}] (let [amount-input (atom nil) @@ -82,12 +78,6 @@ (defview send-transaction [] (letsubs [transaction [:wallet.send/transaction] - chain [:ethereum/chain-keyword] - scroll (atom nil) - network-status [:network-status] - all-tokens [:wallet/all-tokens]] + scroll (atom nil)] [send-transaction-view {:transaction transaction - :scroll scroll - :chain chain - :all-tokens all-tokens - :network-status network-status}])) + :scroll scroll}])) diff --git a/src/status_im/wallet/core.cljs b/src/status_im/wallet/core.cljs index b0578fbe75..3f5f3748b2 100644 --- a/src/status_im/wallet/core.cljs +++ b/src/status_im/wallet/core.cljs @@ -4,6 +4,7 @@ [status-im.multiaccounts.update.core :as multiaccounts.update] [status-im.constants :as constants] [status-im.ethereum.core :as ethereum] + [status-im.ethereum.eip55 :as eip55] [status-im.ethereum.json-rpc :as json-rpc] [status-im.ethereum.tokens :as tokens] [status-im.i18n :as i18n] @@ -37,8 +38,8 @@ (json-rpc/call {:method "eth_getBalance" :params [address "latest"] - :on-success #(re-frame/dispatch [:wallet.callback/update-balance-success address %]) - :on-error #(re-frame/dispatch [:wallet.callback/update-balance-fail %])})))) + :on-success #(re-frame/dispatch [::update-balance-success address %]) + :on-error #(re-frame/dispatch [::update-balance-fail %])})))) ;; TODO(oskarth): At some point we want to get list of relevant ;; assets to get prices for @@ -56,6 +57,7 @@ (assoc-in db [:wallet :errors error-type] (or err :unknown-error))) (fx/defn on-update-prices-fail + {::events [::update-prices-fail]} [{:keys [db]} err] (log/debug "Unable to get prices: " err) {:db (-> db @@ -63,14 +65,16 @@ (assoc :prices-loading? false))}) (fx/defn on-update-balance-fail + {:events [::update-balance-fail]} [{:keys [db]} err] (log/debug "Unable to get balance: " err) {:db (-> db (assoc-error-message :balance-update :error-unable-to-get-balance))}) (fx/defn on-update-token-balance-fail - [{:keys [db]} symbol err] - (log/debug "Unable to get token " symbol "balance: " err) + {:events [::update-token-balance-fail]} + [{:keys [db]} err] + (log/debug "Unable to get tokens balances: " err) {:db (-> db (assoc-error-message :balance-update :error-unable-to-get-token-balance))}) @@ -142,24 +146,48 @@ (validate-token-symbol! token) (validate-token-name! token)))) +(defn- clean-up-results + "remove empty balances + if there is no visible assets, returns all positive balances + otherwise return only the visible assets balances" + [results tokens assets] + (let [balances + (reduce (fn [acc [address balances]] + (let [pos-balances + (reduce (fn [acc [token-address token-balance]] + (if (pos? token-balance) + (let [token-symbol (get tokens (name token-address))] + (if (or (empty? assets) + (assets token-symbol)) + (assoc acc token-symbol token-balance) + acc)) + acc)) + {} + balances)] + (if (not-empty pos-balances) + (assoc acc (eip55/address->checksum (name address)) pos-balances) + acc))) + {} + results)] + (when (not-empty balances) + balances))) + (re-frame/reg-fx :wallet/get-tokens-balances (fn [{:keys [addresses tokens assets]}] - ;;TODO not great to have so many calls , should be optimized, there is wallet_getTokensBalances why wouldn't use it? - (doseq [{:keys [address symbol]} tokens] - (doseq [account-address addresses] - (json-rpc/eth-call - {:contract address - :method "balanceOf(address)" - :params [account-address] - :outputs ["uint256"] - :on-success (fn [[balance]] - (if (and assets (assets symbol)) - (re-frame/dispatch [:wallet.callback/update-token-balance-success account-address symbol balance]) - ;; NOTE: when there it is not a visible assets we make an initialization round - (when (pos? balance) - (re-frame/dispatch [:wallet/token-found account-address symbol balance])))) - :on-error #(re-frame/dispatch [:wallet.callback/update-token-balance-fail symbol %])}))))) + (let [tokens-addresses (keys tokens)] + (json-rpc/call + {:method "wallet_getTokensBalances" + :params [addresses tokens-addresses] + :on-success + (fn [results] + (when-let [balances (clean-up-results results tokens assets)] + (re-frame/dispatch (if (empty? assets) + ;; NOTE: when there it is not a visible + ;; assets we make an initialization round + [::tokens-found balances] + [::update-tokens-balances-success balances])))) + :on-error #(re-frame/dispatch [::update-token-balance-fail %])})))) (defn clear-error-message [db error-type] (update-in db [:wallet :errors] dissoc error-type)) @@ -193,7 +221,10 @@ chain (ethereum/chain-keyword db) assets (get-in settings [:wallet :visible-tokens chain]) tokens (->> (tokens/tokens-for all-tokens chain) - (remove #(or (:hidden? %))))] + (remove #(or (:hidden? %))) + (reduce (fn [acc {:keys [address symbol]}] + (assoc acc address symbol)) + {}))] (when (not= network-status :offline) (fx/merge cofx @@ -215,7 +246,7 @@ {:keys [address chaos-mode? settings]} :multiaccount :as db} :db}] (let [chain (ethereum/chain-keyword db) mainnet? (= :mainnet chain) - assets (get-in settings [:wallet :visible-tokens chain]) + assets (get-in settings [:wallet :visible-tokens chain] #{}) tokens (tokens-symbols assets all-tokens chain) currency-id (or (get-in settings [:wallet :currency]) :usd) currency (get constants/currencies currency-id)] @@ -227,8 +258,8 @@ (wallet.utils/exchange-symbol))]) :to [(:code currency)] :mainnet? mainnet? - :success-event :wallet.callback/update-prices-success - :error-event :wallet.callback/update-prices-fail + :success-event ::update-prices-success + :error-event ::update-prices-fail :chaos-mode? chaos-mode?} :db @@ -242,20 +273,18 @@ (disj ids id))) (fx/defn on-update-prices-success + {:events [::update-prices-success]} [{:keys [db]} prices] {:db (assoc db :prices prices :prices-loading? false)}) (fx/defn update-balance + {:events [::update-balance-success]} [{:keys [db]} address balance] - {:db (-> db - (assoc-in [:wallet :accounts address :balance :ETH] (money/bignumber balance)))}) - -(fx/defn update-token-balance - [{:keys [db]} address symbol balance] - {:db (-> db - (assoc-in [:wallet :accounts address :balance symbol] (money/bignumber balance)))}) + {:db (assoc-in db + [:wallet :accounts (eip55/address->checksum address) :balance :ETH] + (money/bignumber balance))}) (defn update-toggle-in-settings [{{:keys [multiaccount] :as db} :db} symbol checked?] @@ -268,6 +297,38 @@ (let [new-settings (update-toggle-in-settings cofx symbol checked?)] (multiaccounts.update/update-settings cofx new-settings {}))) +(fx/defn update-tokens-balances + {:events [::update-tokens-balances-success]} + [{:keys [db]} balances] + (let [accounts (get-in db [:wallet :accounts])] + {:db (assoc-in db + [:wallet :accounts] + (reduce (fn [acc [address balances]] + (assoc-in acc + [address :balance] + (reduce (fn [acc [token-symbol balance]] + (assoc acc + token-symbol + (money/bignumber balance))) + (get-in accounts [address :balance]) + balances))) + accounts + balances))})) + +(fx/defn configure-token-balance-and-visibility + {:events [::tokens-found]} + [{:keys [db] :as cofx} balances] + (let [chain (ethereum/chain-keyword db) + settings (get-in db [:multiaccount :settings]) + visible-tokens (into #{} (flatten (map keys (vals balances)))) + new-settings (assoc-in settings + [:wallet :visible-tokens chain] + visible-tokens)] + (fx/merge cofx + (multiaccounts.update/update-settings cofx new-settings {}) + (update-tokens-balances balances) + (update-prices)))) + (fx/defn add-custom-token [{:keys [db] :as cofx} {:keys [symbol address] :as token}] (let [chain (ethereum/chain-keyword db) @@ -282,24 +343,18 @@ new-settings (update-in settings [:wallet :custom-tokens chain] dissoc address)] (multiaccounts.update/update-settings cofx new-settings {}))) -(fx/defn configure-token-balance-and-visibility - [cofx address symbol balance] - (fx/merge cofx - (toggle-visible-token symbol true) - ;;TODO(goranjovic): move `update-token-balance-success` function to wallet models - (update-token-balance address symbol balance))) - -(defn set-and-validate-amount-db [db amount symbol decimals] - (let [{:keys [value error]} (wallet.db/parse-amount amount decimals)] - (-> db - (assoc-in [:wallet :send-transaction :amount] (money/formatted->internal value symbol decimals)) - (assoc-in [:wallet :send-transaction :amount-text] amount) - (assoc-in [:wallet :send-transaction :amount-error] error)))) - (fx/defn set-and-validate-amount {:events [:wallet.send/set-and-validate-amount]} - [{:keys [db]} amount symbol decimals] - {:db (set-and-validate-amount-db db amount symbol decimals)}) + [{:keys [db]} amount] + (let [chain (ethereum/chain-keyword db) + all-tokens (:wallet/all-tokens db) + symbol (get-in db [:wallet :send-transaction :symbol]) + {:keys [decimals]} (tokens/asset-for all-tokens chain symbol) + {:keys [value error]} (wallet.db/parse-amount amount decimals)] + {:db (-> db + (assoc-in [:wallet :send-transaction :amount] (money/formatted->internal value symbol decimals)) + (assoc-in [:wallet :send-transaction :amount-text] amount) + (assoc-in [:wallet :send-transaction :amount-error] error))})) (fx/defn set-symbol {:events [:wallet.send/set-symbol]}