From ed53fecf47d52ee17941e87a52a90d0e1467c7ba Mon Sep 17 00:00:00 2001 From: Mohamed Javid <19339952+smohamedjavid@users.noreply.github.com> Date: Fri, 15 Dec 2023 01:08:16 +0530 Subject: [PATCH] Added support for different currencies in wallet accounts price calculation (#18078) This commit: - adds support for different currencies in token price calculation in the new wallet UI. - fixes the token units and prices displayed in the individual account screen Signed-off-by: Mohamed Javid <19339952+smohamedjavid@users.noreply.github.com> --- src/status_im/currency/core.cljs | 3 +- src/status_im2/constants.cljs | 1 + .../contexts/wallet/account/view.cljs | 5 +- .../contexts/wallet/common/utils.cljs | 17 +-- src/status_im2/contexts/wallet/events.cljs | 17 ++- .../wallet/send/select_asset/view.cljs | 2 +- src/status_im2/subs/profile.cljs | 14 +++ src/status_im2/subs/profile_test.cljs | 114 ++++++++++++++++++ src/status_im2/subs/wallet/wallet.cljs | 54 +++++---- 9 files changed, 186 insertions(+), 41 deletions(-) create mode 100644 src/status_im2/subs/profile_test.cljs diff --git a/src/status_im/currency/core.cljs b/src/status_im/currency/core.cljs index 51a6126ea2..10b18199b5 100644 --- a/src/status_im/currency/core.cljs +++ b/src/status_im/currency/core.cljs @@ -15,5 +15,6 @@ (multiaccounts.update/multiaccount-update :currency currency - {}) + ;; on changing currency, we should fetch tokens prices again + {:on-success #(rf/dispatch [:wallet/get-wallet-token])}) (prices/update-prices))) diff --git a/src/status_im2/constants.cljs b/src/status_im2/constants.cljs index 73c730bda6..ba1591c773 100644 --- a/src/status_im2/constants.cljs +++ b/src/status_im2/constants.cljs @@ -105,6 +105,7 @@ (def ^:const profile-default-color :blue) (def ^:const profile-name-max-length 24) +(def ^:const profile-default-currency :usd) (def ^:const profile-pictures-show-to-contacts-only 1) (def ^:const profile-pictures-show-to-everyone 2) diff --git a/src/status_im2/contexts/wallet/account/view.cljs b/src/status_im2/contexts/wallet/account/view.cljs index 5c5bb7fe2e..a5d987f411 100644 --- a/src/status_im2/contexts/wallet/account/view.cljs +++ b/src/status_im2/contexts/wallet/account/view.cljs @@ -35,11 +35,12 @@ [] (let [selected-tab (reagent/atom first-tab-id)] (fn [] - (let [{:keys [name color balance watch-only?]} (rf/sub [:wallet/current-viewing-account])] + (let [{:keys [name color balance watch-only?]} (rf/sub [:wallet/current-viewing-account]) + currency-symbol (rf/sub [:profile/currency-symbol])] [rn/view {:style {:flex 1}} [account-switcher/view {:on-press #(rf/dispatch [:wallet/close-account-page])}] [quo/account-overview - {:current-value (utils/prettify-balance balance) + {:current-value (utils/prettify-balance currency-symbol balance) :account-name name :account (if watch-only? :watched-address :default) :customization-color color}] diff --git a/src/status_im2/contexts/wallet/common/utils.cljs b/src/status_im2/contexts/wallet/common/utils.cljs index 87a45a2300..4f8b80907e 100644 --- a/src/status_im2/contexts/wallet/common/utils.cljs +++ b/src/status_im2/contexts/wallet/common/utils.cljs @@ -9,13 +9,13 @@ (first (string/split full-name #" "))) (defn prettify-balance - [balance] + [currency-symbol balance] (let [valid-balance? (and balance (or (number? balance) (.-toFixed balance)))] (as-> balance $ (if valid-balance? $ 0) (.toFixed $ 2) - (str "$" $)))) + (str currency-symbol $)))) (defn get-derivation-path [number-of-accounts] @@ -60,15 +60,18 @@ (defn total-token-fiat-value "Returns the total token fiat value taking into account all token's chains." - [{:keys [market-values-per-currency] :as token}] - (let [usd-price (-> market-values-per-currency :usd :price) + [currency {:keys [market-values-per-currency] :as token}] + (let [price (get-in market-values-per-currency + [currency :price] + (get-in market-values-per-currency + [constants/profile-default-currency :price])) total-units-in-all-chains (total-token-units-in-all-chains token)] - (money/crypto->fiat total-units-in-all-chains usd-price))) + (money/crypto->fiat total-units-in-all-chains price))) (defn calculate-balance-for-account - [{:keys [tokens] :as _account}] + [currency {:keys [tokens] :as _account}] (->> tokens - (map total-token-fiat-value) + (map #(total-token-fiat-value currency %)) (reduce money/add))) (defn network-list diff --git a/src/status_im2/contexts/wallet/events.cljs b/src/status_im2/contexts/wallet/events.cljs index 19086d584d..8fe50930da 100644 --- a/src/status_im2/contexts/wallet/events.cljs +++ b/src/status_im2/contexts/wallet/events.cljs @@ -100,14 +100,21 @@ (let [addresses (->> (get-in db [:wallet :accounts]) vals (map :address))] - {:fx [[:json-rpc/call + {:db (assoc-in db [:wallet :ui :tokens-loading?] true) + :fx [[:json-rpc/call [{:method "wallet_getWalletToken" :params [addresses] :on-success [:wallet/store-wallet-token] - :on-error #(log/info "failed to get wallet token " - {:error % - :event :wallet/get-wallet-token - :params addresses})}]]]}))) + :on-error [:wallet/get-wallet-token-failed addresses]}]]]}))) + +(rf/reg-event-fx + :wallet/get-wallet-token-failed + (fn [{:keys [db]} [params error]] + (log/info "failed to get wallet token " + {:error error + :event :wallet/get-wallet-token + :params params}) + {:db (assoc-in db [:wallet :ui :tokens-loading?] false)})) (defn- fix-balances-per-chain [token] diff --git a/src/status_im2/contexts/wallet/send/select_asset/view.cljs b/src/status_im2/contexts/wallet/send/select_asset/view.cljs index 0e4a599a6b..edbe9f30cf 100644 --- a/src/status_im2/contexts/wallet/send/select_asset/view.cljs +++ b/src/status_im2/contexts/wallet/send/select_asset/view.cljs @@ -20,7 +20,7 @@ (let [on-press #(js/alert "Not implemented yet") total-balance-formatted (.toFixed (:total-balance token) 2) balance-fiat-formatted (.toFixed (:total-balance-fiat token) 2) - currency-symbol "$"] + currency-symbol (rf/sub [:profile/currency-symbol])] [quo/token-network {:token (:symbol token) :label (:name token) diff --git a/src/status_im2/subs/profile.cljs b/src/status_im2/subs/profile.cljs index 39b6dc58dc..e808320109 100644 --- a/src/status_im2/subs/profile.cljs +++ b/src/status_im2/subs/profile.cljs @@ -6,6 +6,7 @@ [re-frame.core :as re-frame] [status-im.fleet.core :as fleet] [status-im.multiaccounts.db :as multiaccounts.db] + [status-im.utils.currency :as currency] [status-im.wallet.utils :as wallet.utils] [status-im2.constants :as constants] [utils.address :as address] @@ -18,6 +19,19 @@ (fn [{:keys [customization-color]}] (or customization-color constants/profile-default-color))) +(re-frame/reg-sub + :profile/currency + :<- [:profile/profile] + (fn [{:keys [currency]}] + (or currency constants/profile-default-currency))) + +(re-frame/reg-sub + :profile/currency-symbol + :<- [:profile/currency] + (fn [currency-id] + (-> (get currency/currencies currency-id) + :symbol))) + (re-frame/reg-sub :profile/onboarding-placeholder-avatar :<- [:mediaserver/port] diff --git a/src/status_im2/subs/profile_test.cljs b/src/status_im2/subs/profile_test.cljs new file mode 100644 index 0000000000..498c0e4722 --- /dev/null +++ b/src/status_im2/subs/profile_test.cljs @@ -0,0 +1,114 @@ +(ns status-im2.subs.profile-test + (:require [cljs.test :refer [is testing use-fixtures]] + [re-frame.db :as rf-db] + status-im2.subs.root + [test-helpers.unit :as h] + [utils.re-frame :as rf])) + +(use-fixtures :each + {:before #(reset! rf-db/app-db {})}) + +(def sample-profile + {:keycard-pairing nil + :send-push-notifications? true + :send-status-updates? true + :key-uid "0x2285f5c1ffd94ade0aa3568bff85f6c06f2860391ba65ccf56276cbc6829a22a" + :backup-enabled? true + :address "0x70F8913fbE0Ca5687F1Fb73068944d6e99B27804" + :mnemonic "lucky veteran business source debris large priority color endless answer strong pave" + :preview-privacy? true + :identicon "" + :use-mailservers? true + :signing-phrase "polo rush vest" + :url-unfurling-mode 1 + :custom-bootnodes-enabled? {} + :log-level "INFO" + :profile-pictures-visibility 2 + :messages-from-contacts-only false + :pinned-mailservers {} + :eip1581-address "0x15636c0aa4036b9f984e8998db085328795b26d8" + :images [{:keyUid "0x2285f5c1ffd94ade0aa3568bff85f6c06f2860391ba65ccf56276cbc6829a22a" + :type "large" + :uri "data:image/jpeg;base64,/9j/2wCEAAgGBgcGBQgHBwcJC=" + :width 240 + :height 240 + :fileSize 15973 + :resizeTarget 240 + :clock 0} + {:keyUid "0x2285f5c1ffd94ade0aa3568bff85f6c06f2860391ba65ccf56276cbc6829a22a" + :type "thumbnail" + :uri "data:image/jpeg;base64,/9j/2wCEAAgGBgcGBQgHBwcJC=" + :width 80 + :height 240 + :fileSize 2558 + :resizeTarget 80 + :clock 0}] + :name "Plush Shiny Songbird" + :latest-derived-path 0 + :compressed-key "zQ3shS6tp3NsQT4RSUFtnTqnBQzC5kt2SZzxZmnPEiNkHetwj" + :wallet-legacy/visible-tokens {:mainnet #{:SNT}} + :kdfIterations 3200 + :ens-name? false + :emoji-hash ["๐Ÿ‘ฎ" "๐Ÿง‘๐Ÿฟโ€๐Ÿญ" "๐Ÿ“ฌ" "๐Ÿ‘ฐโ€โ™€๏ธ" "๐Ÿฆš" "๐Ÿ’ณ" "๐Ÿ‘จ๐Ÿฟโ€๐Ÿณ" "โ˜๏ธ" "๐Ÿคฐ๐Ÿพ" "๐ŸŠ" "โ˜๏ธ" "โ˜”" "๐Ÿ‘ท๐Ÿฝ" "๐Ÿคน๐Ÿพ"] + :wallet-root-address "0x704c9a261b918cb8e522f7fc2bc477c12d0c74ac" + :last-backup 1701832050 + :link-previews-enabled-sites #{} + :networks/networks {} + :wakuv2-config {:Port 0 + :DataDir "" + :LightClient true + :AutoUpdate true + :MaxMessageSize 0 + :KeepAliveInterval 0 + :Nameserver "" + :UseShardAsDefaultTopic false + :PeerExchange true + :StoreCapacity 0 + :UDPPort 0 + :EnableStore false + :EnableFilterFullNode false + :Enabled true + :EnableConfirmations false + :Host "0.0.0.0" + :CustomNodes {} + :FullNode false + :EnableDiscV5 true + :DiscoveryLimit 20 + :StoreSeconds 0} + :current-user-visibility-status {:clock 1701798568 + :text "" + :status-type 1} + :gifs/api-key "" + :currency :usd + :gifs/favorite-gifs nil + :customization-color :magenta + :default-sync-period 777600 + :photo-path "" + :dapps-address "0x52fB56556A039244CED121AFB9ec829788Db78c8" + :custom-bootnodes {} + :display-name "Alisher Y" + :gifs/recent-gifs nil + :appearance 0 + :link-preview-request-enabled true + :profile-pictures-show-to 2 + :timestamp 1701798892 + :device-name "" + :colorId 2 + :networks/current-network "mainnet_rpc" + :mutual-contact-enabled? false + :public-key + "0x0445b4d3a20f9fcf95b9e669857f83a073e7fdb7b79d0ac03ffb601d6889c413fa86282a2b2bed46ecf7d499807c1567549367a4eaa2b7b925067d44562d93cfa6" + :colorHash [[3 25] [4 3] [5 4] [2 0] [1 10] [5 2] [2 4] [1 17] [3 23] [2 19] [4 1]] + :installation-id "cee7e269-1ca7-4468-a1dd-e60e5cfb0894"}) + +(h/deftest-sub :profile/currency + [sub-name] + (testing "returns the selected currency of user" + (swap! rf-db/app-db #(assoc % :profile/profile sample-profile)) + (is (match? :usd (rf/sub [sub-name]))))) + +(h/deftest-sub :profile/currency-symbol + [sub-name] + (testing "returns the symbol of the user's selected currency" + (swap! rf-db/app-db #(assoc % :profile/profile sample-profile)) + (is (match? "$" (rf/sub [sub-name]))))) diff --git a/src/status_im2/subs/wallet/wallet.cljs b/src/status_im2/subs/wallet/wallet.cljs index bd8db704dc..35c91c61d8 100644 --- a/src/status_im2/subs/wallet/wallet.cljs +++ b/src/status_im2/subs/wallet/wallet.cljs @@ -1,6 +1,7 @@ (ns status-im2.subs.wallet.wallet (:require [clojure.string :as string] [re-frame.core :as rf] + [status-im2.constants :as constants] [status-im2.contexts.wallet.common.utils :as utils] [utils.number])) @@ -69,23 +70,25 @@ (rf/reg-sub :wallet/balances :<- [:wallet/accounts] - (fn [accounts] + :<- [:profile/currency] + (fn [[accounts currency]] (zipmap (map :address accounts) - (map utils/calculate-balance-for-account accounts)))) + (map #(utils/calculate-balance-for-account currency %) accounts)))) (rf/reg-sub :wallet/account-cards-data :<- [:wallet/accounts] :<- [:wallet/balances] :<- [:wallet/tokens-loading?] - (fn [[accounts balances tokens-loading?]] + :<- [:profile/currency-symbol] + (fn [[accounts balances tokens-loading? currency-symbol]] (mapv (fn [{:keys [color address watch-only?] :as account}] (assoc account :customization-color color :type (if watch-only? :watch-only :empty) :on-press #(rf/dispatch [:wallet/navigate-to-account address]) :loading? tokens-loading? - :balance (utils/prettify-balance (get balances address)))) + :balance (utils/prettify-balance currency-symbol (get balances address)))) accounts))) (rf/reg-sub @@ -131,31 +134,32 @@ (remove #(:watch-only? %) accounts))) (defn- calc-token-value - [{:keys [market-values-per-currency] :as item} chain-id] - (let [crypto-value (utils/token-value-in-chain item chain-id) - market-values (:usd market-values-per-currency) - {:keys [price change-pct-24hour]} market-values - fiat-change (utils/calculate-fiat-change crypto-value change-pct-24hour)] - (when (and crypto-value (seq (:name item))) - {:token (keyword (string/lower-case (:symbol item))) - :token-name (:name item) - :state :default - :status (cond - (pos? change-pct-24hour) :positive - (neg? change-pct-24hour) :negative - :else :empty) - :customization-color :blue - :values {:crypto-value crypto-value - :fiat-value (utils/prettify-balance (* crypto-value price)) - :percentage-change (.toFixed change-pct-24hour 2) - :fiat-change (utils/prettify-balance fiat-change)}}))) + [{:keys [market-values-per-currency] :as token} color currency currency-symbol] + (let [token-units (utils/total-token-units-in-all-chains token) + fiat-value (utils/total-token-fiat-value currency token) + market-values (get market-values-per-currency + currency + (get market-values-per-currency + constants/profile-default-currency)) + {:keys [change-pct-24hour]} market-values] + {:token (:symbol token) + :token-name (:name token) + :state :default + :status (cond + (pos? change-pct-24hour) :positive + (neg? change-pct-24hour) :negative + :else :empty) + :customization-color color + :values {:crypto-value token-units + :fiat-value (utils/prettify-balance currency-symbol fiat-value)}})) (rf/reg-sub :wallet/account-token-values :<- [:wallet/current-viewing-account] - :<- [:chain-id] - (fn [[current-account chain-id]] - (mapv #(calc-token-value % chain-id) (:tokens current-account)))) + :<- [:profile/currency] + :<- [:profile/currency-symbol] + (fn [[{:keys [tokens color]} currency currency-symbol]] + (mapv #(calc-token-value % color currency currency-symbol) tokens))) (rf/reg-sub :wallet/network-preference-details