[Feature] Wallet - Network based assets and fiat balance calculation (#19150)

This commit:

(UI changes)

- adds the feature to filter assets (tokens and collectibles) and balances based on networks
- fixes network color for eth not shown on the multichain address (e.g. Account Options bottom sheet)
- fixes blur type in the confirm button in the network preferences sheet
- fixes the User ability to unselect all networks in the network preferences sheet
- fixes account address and color not shown in network-preferences sheet on Shell > Share Multichain address
- added STT token image

(Non-UI changes)

- Refactors the functions used for balance calculations and network details


Signed-off-by: Mohamed Javid <19339952+smohamedjavid@users.noreply.github.com>
This commit is contained in:
Mohamed Javid 2024-04-05 17:18:35 +05:30 committed by GitHub
parent 5fc23816a6
commit 9ba6c6262e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
36 changed files with 675 additions and 350 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

@ -456,7 +456,9 @@
(def ^:const optimism-network-name :optimism) (def ^:const optimism-network-name :optimism)
(def ^:const arbitrum-network-name :arbitrum) (def ^:const arbitrum-network-name :arbitrum)
(def ^:const default-network-names #{mainnet-network-name optimism-network-name arbitrum-network-name}) (def ^:const default-network-names [mainnet-network-name optimism-network-name arbitrum-network-name])
(def ^:const default-network-count (count default-network-names))
(def ^:const chain-id-separator ":") (def ^:const chain-id-separator ":")

View File

@ -33,7 +33,10 @@
(assoc :test-ID stack-id (assoc :test-ID stack-id
:icon icon :icon icon
:icon-color-anim icon-color :icon-color-anim icon-color
:on-press #(animation/bottom-tab-on-press stack-id true) :on-press (fn []
(when-not (= stack-id :wallet-stack)
(rf/dispatch [:wallet/reset-selected-networks]))
(animation/bottom-tab-on-press stack-id true))
:accessibility-label (str (name stack-id) "-tab") :accessibility-label (str (name stack-id) "-tab")
:customization-color customization-color))])) :customization-color customization-color))]))

View File

@ -9,7 +9,7 @@
[status-im.contexts.shell.jump-to.constants :as shell.constants] [status-im.contexts.shell.jump-to.constants :as shell.constants]
[status-im.contexts.shell.jump-to.state :as state] [status-im.contexts.shell.jump-to.state :as state]
[status-im.contexts.shell.jump-to.utils :as utils] [status-im.contexts.shell.jump-to.utils :as utils]
[status-im.contexts.wallet.home.view :as wallet-new] [status-im.contexts.wallet.home.view :as wallet]
[utils.re-frame :as rf])) [utils.re-frame :as rf]))
(defn load-stack? (defn load-stack?
@ -32,7 +32,7 @@
(case stack-id (case stack-id
:communities-stack [:f> communities/view] :communities-stack [:f> communities/view]
:chats-stack [:f> chat/view] :chats-stack [:f> chat/view]
:wallet-stack [wallet-new/view] :wallet-stack [wallet/view]
:browser-stack [browser.stack/browser-stack] :browser-stack [browser.stack/browser-stack]
[:<>])]) [:<>])])

View File

@ -37,7 +37,7 @@
:on-text-long-press #(rf/dispatch [:share/copy-text-and-show-toast :on-text-long-press #(rf/dispatch [:share/copy-text-and-show-toast
{:text-to-copy universal-profile-url {:text-to-copy universal-profile-url
:post-copy-message (i18n/label :t/link-to-profile-copied)}]) :post-copy-message (i18n/label :t/link-to-profile-copied)}])
:profile-picture (:uri (profile.utils/photo profile)) :profile-picture (profile.utils/photo profile)
:full-name (profile.utils/displayed-name profile) :full-name (profile.utils/displayed-name profile)
:customization-color customization-color}]] :customization-color customization-color}]]

View File

@ -6,6 +6,7 @@
[react-native.platform :as platform] [react-native.platform :as platform]
[react-native.share :as share] [react-native.share :as share]
[reagent.core :as reagent] [reagent.core :as reagent]
[status-im.constants :as constants]
[status-im.contexts.shell.share.style :as style] [status-im.contexts.shell.share.style :as style]
[status-im.contexts.shell.share.wallet.style :as wallet-style] [status-im.contexts.shell.share.wallet.style :as wallet-style]
[status-im.contexts.wallet.common.utils :as utils] [status-im.contexts.wallet.common.utils :as utils]
@ -33,25 +34,28 @@
:isNewTask true}))) :isNewTask true})))
(defn- open-preferences (defn- open-preferences
[selected-networks] [selected-networks account]
(rf/dispatch [:show-bottom-sheet (rf/dispatch
[:show-bottom-sheet
{:theme :dark {:theme :dark
:shell? true :shell? true
:content :content (fn []
(fn []
[network-preferences/view [network-preferences/view
{:blur? true {:blur? true
:selected-networks (set @selected-networks) :selected-networks (set @selected-networks)
:account account
:button-label (i18n/label :t/display)
:on-save (fn [chain-ids] :on-save (fn [chain-ids]
(rf/dispatch [:hide-bottom-sheet]) (rf/dispatch [:hide-bottom-sheet])
(reset! selected-networks (map #(get utils/id->network %) (reset! selected-networks (map #(get utils/id->network %)
chain-ids)))}])}])) chain-ids)))}])}]))
(defn- wallet-qr-code-item (defn- wallet-qr-code-item
[{:keys [account index]}] [{:keys [account index]}]
(let [{window-width :width} (rn/get-window) (let [{window-width :width} (rn/get-window)
selected-networks (reagent/atom [:ethereum :optimism :arbitrum]) selected-networks (reagent/atom constants/default-network-names)
wallet-type (reagent/atom :legacy) wallet-type (reagent/atom :legacy)
on-settings-press #(open-preferences selected-networks) on-settings-press #(open-preferences selected-networks account)
on-legacy-press #(reset! wallet-type :legacy) on-legacy-press #(reset! wallet-type :legacy)
on-multichain-press #(reset! wallet-type :multichain)] on-multichain-press #(reset! wallet-type :multichain)]
(fn [] (fn []

View File

@ -6,6 +6,7 @@
[react-native.safe-area :as safe-area] [react-native.safe-area :as safe-area]
[react-native.share :as share] [react-native.share :as share]
[reagent.core :as reagent] [reagent.core :as reagent]
[status-im.constants :as constants]
[status-im.contexts.wallet.account.share-address.style :as style] [status-im.contexts.wallet.account.share-address.style :as style]
[status-im.contexts.wallet.common.utils :as utils] [status-im.contexts.wallet.common.utils :as utils]
[status-im.contexts.wallet.sheets.network-preferences.view :as network-preferences] [status-im.contexts.wallet.sheets.network-preferences.view :as network-preferences]
@ -34,13 +35,13 @@
[selected-networks] [selected-networks]
(let [on-save (fn [chain-ids] (let [on-save (fn [chain-ids]
(rf/dispatch [:hide-bottom-sheet]) (rf/dispatch [:hide-bottom-sheet])
(reset! selected-networks (map #(if (= % 1) :mainnet (utils/id->network %)) (reset! selected-networks (map utils/id->network chain-ids)))
chain-ids)))
sheet-content (fn [] sheet-content (fn []
[network-preferences/view [network-preferences/view
{:blur? true {:blur? true
:selected-networks (set @selected-networks) :selected-networks (set @selected-networks)
:on-save on-save}])] :on-save on-save
:button-label (i18n/label :t/display)}])]
(rf/dispatch [:show-bottom-sheet (rf/dispatch [:show-bottom-sheet
{:theme :dark {:theme :dark
:shell? true :shell? true
@ -53,7 +54,7 @@
wallet-type (reagent/atom :legacy) wallet-type (reagent/atom :legacy)
;; Design team is yet to confirm the default selected networks here. Should be the current ;; Design team is yet to confirm the default selected networks here. Should be the current
;; selected for the account or all the networks always ;; selected for the account or all the networks always
selected-networks (reagent/atom [:mainnet :optimism :arbitrum]) selected-networks (reagent/atom constants/default-network-names)
on-settings-press #(open-preferences selected-networks) on-settings-press #(open-preferences selected-networks)
on-legacy-press #(reset! wallet-type :legacy) on-legacy-press #(reset! wallet-type :legacy)
on-multichain-press #(reset! wallet-type :multichain)] on-multichain-press #(reset! wallet-type :multichain)]

View File

@ -8,7 +8,8 @@
(defn view (defn view
[] []
(let [tokens-loading? (rf/sub [:wallet/tokens-loading?]) (let [tokens-loading? (rf/sub [:wallet/tokens-loading?])
tokens (rf/sub [:wallet/account-token-values])] tokens (rf/sub [:wallet/current-viewing-account-token-values])
{:keys [watch-only?]} (rf/sub [:wallet/current-viewing-account])]
(if tokens-loading? (if tokens-loading?
[quo/skeleton-list [quo/skeleton-list
{:content :assets {:content :assets
@ -18,4 +19,5 @@
{:render-fn token-value/view {:render-fn token-value/view
:style {:flex 1} :style {:flex 1}
:data tokens :data tokens
:render-data {:watch-only? watch-only?}
:content-container-style {:padding-horizontal 8}}]))) :content-container-style {:padding-horizontal 8}}])))

View File

@ -12,7 +12,7 @@
(defn view (defn view
[{:keys [selected-tab]}] [{:keys [selected-tab]}]
(let [collectible-list (rf/sub [:wallet/current-viewing-account-collectibles])] (let [collectible-list (rf/sub [:wallet/current-viewing-account-collectibles-in-selected-networks])]
[rn/view {:style {:flex 1}} [rn/view {:style {:flex 1}}
(case selected-tab (case selected-tab
:assets [assets/view] :assets [assets/view]

View File

@ -17,17 +17,17 @@
(let [network (rf/sub [:wallet/network-details-by-chain-id chain-id]) (let [network (rf/sub [:wallet/network-details-by-chain-id chain-id])
currency (rf/sub [:profile/currency]) currency (rf/sub [:profile/currency])
currency-symbol (rf/sub [:profile/currency-symbol]) currency-symbol (rf/sub [:profile/currency-symbol])
all-balances (:balances-per-chain token) balance (utils/calculate-total-token-balance token [chain-id])
balance-for-chain (utils/get-balance-for-chain all-balances chain-id) crypto-value (utils/get-standard-crypto-format token balance)
crypto-formatted (or (:balance balance-for-chain) "0.00") fiat-value (utils/calculate-token-fiat-value
fiat-value (utils/token-fiat-value currency {:currency currency
(or (:balance balance-for-chain) 0) :balance balance
token) :token token})
fiat-formatted (utils/get-standard-fiat-format crypto-formatted currency-symbol fiat-value)] fiat-formatted (utils/get-standard-fiat-format crypto-value currency-symbol fiat-value)]
[quo/network-list [quo/network-list
{:label (name network-name) {:label (name network-name)
:network-image (quo.resources/get-network (:network-name network)) :network-image (quo.resources/get-network (:network-name network))
:token-value (str crypto-formatted " " (:symbol token)) :token-value (str crypto-value " " (:symbol token))
:fiat-value fiat-formatted :fiat-value fiat-formatted
:on-press #(rf/dispatch [:wallet/select-bridge-network :on-press #(rf/dispatch [:wallet/select-bridge-network
{:network-chain-id chain-id {:network-chain-id chain-id

View File

@ -1,9 +1,9 @@
(ns status-im.contexts.wallet.common.account-switcher.view (ns status-im.contexts.wallet.common.account-switcher.view
(:require [quo.core :as quo] (:require
[quo.core :as quo]
[status-im.contexts.wallet.sheets.account-options.view :as account-options] [status-im.contexts.wallet.sheets.account-options.view :as account-options]
[status-im.contexts.wallet.sheets.network-filter.view :as network-filter] [status-im.contexts.wallet.sheets.network-filter.view :as network-filter]
[status-im.contexts.wallet.sheets.select-account.view :as select-account] [status-im.contexts.wallet.sheets.select-account.view :as select-account]
[status-im.feature-flags :as ff]
[utils.re-frame :as rf])) [utils.re-frame :as rf]))
(defn get-bottom-sheet-args (defn get-bottom-sheet-args
@ -20,7 +20,7 @@
accessibility-label :top-bar accessibility-label :top-bar
switcher-type :account-options}}] switcher-type :account-options}}]
(let [{:keys [color emoji watch-only?]} (rf/sub [:wallet/current-viewing-account]) (let [{:keys [color emoji watch-only?]} (rf/sub [:wallet/current-viewing-account])
networks (rf/sub [:wallet/network-details])] networks (rf/sub [:wallet/selected-network-details])]
[quo/page-nav [quo/page-nav
{:type (or type :no-title) {:type (or type :no-title)
:icon-name icon-name :icon-name icon-name
@ -29,10 +29,7 @@
:on-press on-press :on-press on-press
:accessibility-label accessibility-label :accessibility-label accessibility-label
:networks networks :networks networks
:networks-on-press #(ff/alert ::ff/wallet.network-filter :networks-on-press #(rf/dispatch [:show-bottom-sheet {:content network-filter/view}])
(fn []
(rf/dispatch [:show-bottom-sheet
{:content network-filter/view}])))
:right-side :account-switcher :right-side :account-switcher
:account-switcher {:customization-color color :account-switcher {:customization-color color
:on-press #(rf/dispatch [:show-bottom-sheet :on-press #(rf/dispatch [:show-bottom-sheet

View File

@ -6,10 +6,12 @@
[utils.re-frame :as rf])) [utils.re-frame :as rf]))
(defn- asset-component (defn- asset-component
[token _ _ {:keys [currency currency-symbol on-token-press]}] [{:keys [total-balance] :as token} _ _ {:keys [currency currency-symbol on-token-press]}]
(let [token-units (utils/total-token-units-in-all-chains token) (let [fiat-value (utils/calculate-token-fiat-value
crypto-formatted (utils/get-standard-crypto-format token token-units) {:currency currency
fiat-value (utils/total-token-fiat-value currency token) :balance total-balance
:token token})
crypto-formatted (utils/get-standard-crypto-format token total-balance)
fiat-formatted (utils/get-standard-fiat-format crypto-formatted currency-symbol fiat-value)] fiat-formatted (utils/get-standard-fiat-format crypto-formatted currency-symbol fiat-value)]
[quo/token-network [quo/token-network
{:token (:symbol token) {:token (:symbol token)
@ -21,7 +23,7 @@
(defn view (defn view
[{:keys [search-text on-token-press]}] [{:keys [search-text on-token-press]}]
(let [filtered-tokens (rf/sub [:wallet/tokens-filtered search-text]) (let [filtered-tokens (rf/sub [:wallet/current-viewing-account-tokens-filtered search-text])
currency (rf/sub [:profile/currency]) currency (rf/sub [:profile/currency])
currency-symbol (rf/sub [:profile/currency-symbol])] currency-symbol (rf/sub [:profile/currency-symbol])]
[rn/flat-list [rn/flat-list

View File

@ -43,37 +43,3 @@
:image :icon-avatar :image :icon-avatar
:image-props {:icon (status.resources/get-service-image :latamex)} :image-props {:icon (status.resources/get-service-image :latamex)}
:on-press #(rn/open-url "https://latamex.com")}]) :on-press #(rn/open-url "https://latamex.com")}])
(defn bridge-token-list
[networks-list]
[{:token :snt
:name "Status"
:token-value "0.00 SNT"
:fiat-value "€0.00"
:networks networks-list
:state :default
:symbol "STT"
:customization-color :blue}
{:token :eth
:name "Ethereum"
:token-value "0.00 ETH"
:fiat-value "€0.00"
:networks networks-list
:state :default
:symbol "ETH"
:customization-color :blue}
{:token :dai
:name "Dai"
:token-value "0.00 DAI"
:fiat-value "€0.00"
:networks networks-list
:state :default
:symbol "DAI"
:customization-color :blue}])
(def secret-phrase
["witch" "collapse" "practice" "feed" "shame" "open" "lion"
"collapse" "umbrella" "fabric" "sadness" "obligue"])
(def random-words
["cousin" "roof" "minute" "swallow" "wing" "motion" "stomach"
"abuse" "banner" "noble" "poet" "wrist"])

View File

@ -5,7 +5,7 @@
(defn token-value-drawer (defn token-value-drawer
[token] [token]
(let [token-data (first (rf/sub [:wallet/tokens-filtered (:token token)]))] (let [token-data (first (rf/sub [:wallet/current-viewing-account-tokens-filtered (:token token)]))]
[:<> [:<>
[quo/action-drawer [quo/action-drawer
[[{:icon :i/buy [[{:icon :i/buy
@ -41,8 +41,7 @@
:on-press #(js/alert "to be implemented")}]]]])) :on-press #(js/alert "to be implemented")}]]]]))
(defn view (defn view
[item] [item _ _ {:keys [watch-only?]}]
(let [{:keys [watch-only?]} (rf/sub [:wallet/current-viewing-account])]
[quo/token-value [quo/token-value
(cond-> item (cond-> item
(not watch-only?) (not watch-only?)
@ -50,4 +49,4 @@
#(rf/dispatch #(rf/dispatch
[:show-bottom-sheet [:show-bottom-sheet
{:content (fn [] [token-value-drawer item]) {:content (fn [] [token-value-drawer item])
:selected-item (fn [] [quo/token-value item])}])))])) :selected-item (fn [] [quo/token-value item])}])))])

View File

@ -86,61 +86,48 @@
(str "<" (remove-trailing-zeroes (.toFixed one-cent-value decimals-count))) (str "<" (remove-trailing-zeroes (.toFixed one-cent-value decimals-count)))
(remove-trailing-zeroes (.toFixed token-units decimals-count)))))) (remove-trailing-zeroes (.toFixed token-units decimals-count))))))
(defn total-token-units-in-all-chains (defn get-market-value
[{:keys [balances-per-chain decimals] :as _token}] [currency {:keys [market-values-per-currency]}]
(-> balances-per-chain (or (get-in market-values-per-currency
(total-raw-balance-in-all-chains)
(money/token->unit decimals)))
(defn get-account-by-address
[accounts address]
(some #(when (= (:address %) address) %) accounts))
(defn total-token-fiat-value
"Returns the total token fiat value taking into account all token's chains."
[currency {:keys [market-values-per-currency] :as token}]
(let [price (or (get-in market-values-per-currency
[currency :price]) [currency :price])
(get-in market-values-per-currency (get-in market-values-per-currency
[constants/profile-default-currency :price]) [constants/profile-default-currency :price])
;; NOTE: adding fallback value (zero) in case prices are ;; NOTE: adding fallback value (zero) in case prices are
;; unavailable and to prevent crash on calculating fiat value ;; unavailable and to prevent crash on calculating fiat value
0) 0))
total-units-in-all-chains (total-token-units-in-all-chains token)]
(money/crypto->fiat total-units-in-all-chains price)))
(defn token-fiat-value (defn- filter-chains
"Returns the fiat value for a single token on a given network." [balances-per-chain chain-ids]
[currency raw-balance {:keys [market-values-per-currency]}] (if chain-ids
(let [price (or (get-in market-values-per-currency (select-keys balances-per-chain chain-ids)
[currency :price]) balances-per-chain))
(get-in market-values-per-currency
[constants/profile-default-currency :price])
0)]
(money/crypto->fiat raw-balance price)))
(defn calculate-balance-for-account (defn calculate-total-token-balance
[currency {:keys [tokens] :as _account}] ([token]
(->> tokens (calculate-total-token-balance token nil))
(map #(total-token-fiat-value currency %)) ([{:keys [balances-per-chain decimals]} chain-ids]
(reduce money/add))) (-> balances-per-chain
(filter-chains chain-ids)
(total-raw-balance-in-all-chains)
(money/token->unit decimals))))
(defn calculate-balance-for-token (defn get-account-by-address
[token] [accounts address]
(money/bignumber (some #(when (= (:address %) address) %) accounts))
(money/mul (total-token-units-in-all-chains token)
(-> token :market-values-per-currency :usd :price))))
(defn calculate-balance (defn calculate-token-fiat-value
[tokens-in-account] "Returns the token fiat value for provided raw balance"
(->> tokens-in-account [{:keys [currency balance token]}]
(map #(calculate-balance-for-token %)) (let [price (get-market-value currency token)]
(reduce +))) (money/crypto->fiat balance price)))
(defn calculate-balance-from-tokens (defn calculate-balance-from-tokens
[{:keys [currency tokens]}] [{:keys [currency tokens chain-ids]}]
(->> tokens (->> tokens
(map #(total-token-fiat-value currency %)) (map #(calculate-token-fiat-value
{:currency currency
:balance (calculate-total-token-balance % chain-ids)
:token %}))
(reduce money/add))) (reduce money/add)))
(defn- add-balances-per-chain (defn- add-balances-per-chain
@ -191,38 +178,54 @@
address)) address))
(def id->network (def id->network
{constants/ethereum-mainnet-chain-id :ethereum {constants/ethereum-mainnet-chain-id constants/mainnet-network-name
constants/ethereum-goerli-chain-id :ethereum constants/ethereum-goerli-chain-id constants/mainnet-network-name
constants/ethereum-sepolia-chain-id :ethereum constants/ethereum-sepolia-chain-id constants/mainnet-network-name
constants/optimism-mainnet-chain-id :optimism constants/optimism-mainnet-chain-id constants/optimism-network-name
constants/optimism-goerli-chain-id :optimism constants/optimism-goerli-chain-id constants/optimism-network-name
constants/optimism-sepolia-chain-id :optimism constants/optimism-sepolia-chain-id constants/optimism-network-name
constants/arbitrum-mainnet-chain-id :arbitrum constants/arbitrum-mainnet-chain-id constants/arbitrum-network-name
constants/arbitrum-goerli-chain-id :arbitrum constants/arbitrum-goerli-chain-id constants/arbitrum-network-name
constants/arbitrum-sepolia-chain-id :arbitrum}) constants/arbitrum-sepolia-chain-id constants/arbitrum-network-name})
(defn- get-chain-id (defn- get-chain-id
[testnet-enabled? goerli-enabled?] [{:keys [mainnet-chain-id sepolia-chain-id goerli-chain-id testnet-enabled? goerli-enabled?]}]
(cond (cond
(and testnet-enabled? goerli-enabled?) (and testnet-enabled? goerli-enabled?)
{:eth constants/ethereum-goerli-chain-id goerli-chain-id
:opt constants/optimism-goerli-chain-id
:arb1 constants/arbitrum-goerli-chain-id}
testnet-enabled? testnet-enabled?
{:eth constants/ethereum-sepolia-chain-id sepolia-chain-id
:opt constants/optimism-sepolia-chain-id
:arb1 constants/arbitrum-sepolia-chain-id}
:else :else
{:eth constants/ethereum-mainnet-chain-id mainnet-chain-id))
:opt constants/optimism-mainnet-chain-id
:arb1 constants/arbitrum-mainnet-chain-id}))
(defn short-name->id (defn network->chain-id
[short-name testnet-enabled? goerli-enabled?] [{:keys [network testnet-enabled? goerli-enabled?]}]
(let [chain-id-map (get-chain-id testnet-enabled? goerli-enabled?)] (condp contains? (keyword network)
(get chain-id-map short-name))) #{constants/mainnet-network-name (keyword constants/mainnet-short-name)}
(get-chain-id
{:mainnet-chain-id constants/ethereum-mainnet-chain-id
:sepolia-chain-id constants/ethereum-sepolia-chain-id
:goerli-chain-id constants/ethereum-goerli-chain-id
:testnet-enabled? testnet-enabled?
:goerli-enabled? goerli-enabled?})
#{constants/optimism-network-name (keyword constants/optimism-short-name)}
(get-chain-id
{:mainnet-chain-id constants/optimism-mainnet-chain-id
:sepolia-chain-id constants/optimism-sepolia-chain-id
:goerli-chain-id constants/optimism-goerli-chain-id
:testnet-enabled? testnet-enabled?
:goerli-enabled? goerli-enabled?})
#{constants/arbitrum-network-name (keyword constants/arbitrum-short-name)}
(get-chain-id
{:mainnet-chain-id constants/arbitrum-mainnet-chain-id
:sepolia-chain-id constants/arbitrum-sepolia-chain-id
:goerli-chain-id constants/arbitrum-goerli-chain-id
:testnet-enabled? testnet-enabled?
:goerli-enabled? goerli-enabled?})))
(defn get-standard-fiat-format (defn get-standard-fiat-format
[crypto-value currency-symbol fiat-value] [crypto-value currency-symbol fiat-value]
@ -241,8 +244,11 @@
(defn calculate-token-value (defn calculate-token-value
"This function returns token values in the props of token-value (quo) component" "This function returns token values in the props of token-value (quo) component"
[{:keys [token color currency currency-symbol]}] [{:keys [token color currency currency-symbol]}]
(let [token-units (total-token-units-in-all-chains token) (let [balance (calculate-total-token-balance token)
fiat-value (total-token-fiat-value currency token) fiat-value (calculate-token-fiat-value
{:currency currency
:balance balance
:token token})
market-values (or (get-in token [:market-values-per-currency currency]) market-values (or (get-in token [:market-values-per-currency currency])
(get-in token (get-in token
[:market-values-per-currency [:market-values-per-currency
@ -250,7 +256,7 @@
{:keys [price change-pct-24hour]} market-values {:keys [price change-pct-24hour]} market-values
formatted-token-price (prettify-balance currency-symbol price) formatted-token-price (prettify-balance currency-symbol price)
percentage-change (prettify-percentage-change change-pct-24hour) percentage-change (prettify-percentage-change change-pct-24hour)
crypto-value (get-standard-crypto-format token token-units) crypto-value (get-standard-crypto-format token balance)
fiat-value (get-standard-fiat-format crypto-value fiat-value (get-standard-fiat-format crypto-value
currency-symbol currency-symbol
fiat-value)] fiat-value)]
@ -280,15 +286,10 @@
(let [split-result (string/split input-string #"0x")] (let [split-result (string/split input-string #"0x")]
[(first split-result) (str "0x" (second split-result))])) [(first split-result) (str "0x" (second split-result))]))
(defn get-balance-for-chain
[data chain-id]
(some #(when (= chain-id (:chain-id %)) %) (vals data)))
(defn make-network-item (defn make-network-item
"This function generates props for quo/category component item" "This function generates props for quo/category component item"
[{:keys [network-name] :as _network} [{:keys [network-name color on-change networks state label-props]}]
{:keys [title color on-change networks state label-props] :as _options}] (cond-> {:title (string/capitalize (name network-name))
(cond-> {:title (or title (string/capitalize (name network-name)))
:image :icon-avatar :image :icon-avatar
:image-props {:icon (resources/get-network network-name) :image-props {:icon (resources/get-network network-name)
:size :size-20} :size :size-20}
@ -315,3 +316,21 @@
:else :else
constants/mainnet-chain-ids)) constants/mainnet-chain-ids))
(defn filter-tokens-in-chains
[tokens chain-ids]
(map #(update % :balances-per-chain select-keys chain-ids) tokens))
(defn calculate-balances-per-chain
[{:keys [tokens currency currency-symbol]}]
(->
(reduce (fn [acc {:keys [balances-per-chain decimals] :as token}]
(let [currency-value (get-market-value currency token)
fiat-balance-per-chain (update-vals balances-per-chain
#(-> (money/token->unit (:raw-balance %)
decimals)
(money/crypto->fiat currency-value)))]
(merge-with money/add acc fiat-balance-per-chain)))
{}
tokens)
(update-vals #(prettify-balance currency-symbol %))))

View File

@ -1,5 +1,7 @@
(ns status-im.contexts.wallet.common.utils-test (ns status-im.contexts.wallet.common.utils-test
(:require [cljs.test :refer [deftest is testing]] (:require
[cljs.test :refer [deftest is testing]]
[status-im.constants :as constants]
[status-im.contexts.wallet.common.utils :as utils] [status-im.contexts.wallet.common.utils :as utils]
[utils.money :as money])) [utils.money :as money]))
@ -28,7 +30,6 @@
(is (= (utils/format-derivation-path "m/44'/60'/0'/0/0") "m / 44' / 60' / 0' / 0 / 0")) (is (= (utils/format-derivation-path "m/44'/60'/0'/0/0") "m / 44' / 60' / 0' / 0 / 0"))
(is (= (utils/format-derivation-path "m/44'/60'/0'/0/123") "m / 44' / 60' / 0' / 0 / 123")))) (is (= (utils/format-derivation-path "m/44'/60'/0'/0/123") "m / 44' / 60' / 0' / 0 / 123"))))
(deftest test-get-formatted-derivation-path (deftest test-get-formatted-derivation-path
(testing "get-formatted-derivation-path function" (testing "get-formatted-derivation-path function"
(is (= (utils/get-formatted-derivation-path 5) "m / 44' / 60' / 0' / 0 / 5")) (is (= (utils/get-formatted-derivation-path 5) "m / 44' / 60' / 0' / 0 / 5"))
@ -70,13 +71,13 @@
token-units) token-units)
"<2"))))) "<2")))))
(deftest test-total-token-units-in-all-chains (deftest test-calculate-total-token-balance
(testing "total-token-units-in-all-chains function" (testing "calculate-total-token-balance function"
(let [token {:balances-per-chain {1 {:raw-balance (money/bignumber 100)} (let [token {:balances-per-chain {1 {:raw-balance (money/bignumber 100)}
10 {:raw-balance (money/bignumber 200)} 10 {:raw-balance (money/bignumber 200)}
42161 {:raw-balance (money/bignumber 300)}} 42161 {:raw-balance (money/bignumber 300)}}
:decimals 2}] :decimals 2}]
(is (money/equal-to (utils/total-token-units-in-all-chains token) 6.0))))) (is (money/equal-to (utils/calculate-total-token-balance token) 6.0)))))
(deftest test-get-account-by-address (deftest test-get-account-by-address
(testing "get-account-by-address function" (testing "get-account-by-address function"
@ -115,3 +116,20 @@
(is (= (utils/prettify-percentage-change 1.113454) "1.11")) (is (= (utils/prettify-percentage-change 1.113454) "1.11"))
(is (= (utils/prettify-percentage-change -0.35) "0.35")) (is (= (utils/prettify-percentage-change -0.35) "0.35"))
(is (= (utils/prettify-percentage-change -0.78234) "0.78")))) (is (= (utils/prettify-percentage-change -0.78234) "0.78"))))
(deftest test-network->chain-id
(testing "network->chain-id function"
(is (= (utils/network->chain-id {:network :mainnet :testnet-enabled? false :goerli-enabled? false})
constants/ethereum-mainnet-chain-id))
(is (= (utils/network->chain-id {:network :eth :testnet-enabled? true :goerli-enabled? false})
constants/ethereum-sepolia-chain-id))
(is (= (utils/network->chain-id {:network "optimism" :testnet-enabled? true :goerli-enabled? false})
constants/optimism-sepolia-chain-id))
(is (= (utils/network->chain-id {:network "opt" :testnet-enabled? false :goerli-enabled? true})
constants/optimism-mainnet-chain-id))
(is (= (utils/network->chain-id {:network :opt :testnet-enabled? true :goerli-enabled? true})
constants/optimism-goerli-chain-id))
(is (= (utils/network->chain-id {:network :arb1 :testnet-enabled? false :goerli-enabled? false})
constants/arbitrum-mainnet-chain-id))
(is (= (utils/network->chain-id {:network :arbitrum :testnet-enabled? true :goerli-enabled? false})
constants/arbitrum-sepolia-chain-id))))

View File

@ -0,0 +1,9 @@
(ns status-im.contexts.wallet.db
(:require [status-im.constants :as constants]))
(def network-filter-defaults
{:selector-state :default
:selected-networks (set constants/default-network-names)})
(def defaults
{:ui {:network-filter network-filter-defaults}})

View File

@ -3,9 +3,11 @@
[clojure.string :as string] [clojure.string :as string]
[react-native.background-timer :as background-timer] [react-native.background-timer :as background-timer]
[react-native.platform :as platform] [react-native.platform :as platform]
[status-im.constants :as constants]
[status-im.contexts.wallet.accounts.add-account.address-to-watch.events] [status-im.contexts.wallet.accounts.add-account.address-to-watch.events]
[status-im.contexts.wallet.common.utils :as utils] [status-im.contexts.wallet.common.utils :as utils]
[status-im.contexts.wallet.data-store :as data-store] [status-im.contexts.wallet.data-store :as data-store]
[status-im.contexts.wallet.db :as db]
[status-im.contexts.wallet.events.collectibles] [status-im.contexts.wallet.events.collectibles]
[status-im.contexts.wallet.item-types :as item-types] [status-im.contexts.wallet.item-types :as item-types]
[taoensso.timbre :as log] [taoensso.timbre :as log]
@ -443,3 +445,33 @@
:type :negative :type :negative
:text (i18n/label :t/provider-is-down {:chains chain-names}) :text (i18n/label :t/provider-is-down {:chains chain-names})
:duration 10000}]]])}))) :duration 10000}]]])})))
(defn reset-selected-networks
[{:keys [db]}]
{:db (assoc-in db [:wallet :ui :network-filter] db/network-filter-defaults)})
(rf/reg-event-fx :wallet/reset-selected-networks reset-selected-networks)
(defn update-selected-networks
[{:keys [db]} [network-name]]
(let [selected-networks (get-in db [:wallet :ui :network-filter :selected-networks])
selector-state (get-in db [:wallet :ui :network-filter :selector-state])
contains-network? (contains? selected-networks network-name)
update-fn (if contains-network? disj conj)
networks-count (count selected-networks)]
(cond (= selector-state :default)
{:db (-> db
(assoc-in [:wallet :ui :network-filter :selected-networks] #{network-name})
(assoc-in [:wallet :ui :network-filter :selector-state] :changed))}
;; reset the list
;; - if user is removing the last network in the list
;; - if all networks is selected
(or (and (= networks-count 1) contains-network?)
(and (= (inc networks-count) constants/default-network-count) (not contains-network?)))
{:fx [[:dispatch [:wallet/reset-selected-networks]]]}
:else
{:db (update-in db [:wallet :ui :network-filter :selected-networks] update-fn network-name)})))
(rf/reg-event-fx :wallet/update-selected-networks update-selected-networks)

View File

@ -2,6 +2,8 @@
(:require (:require
[cljs.test :refer-macros [deftest is testing]] [cljs.test :refer-macros [deftest is testing]]
matcher-combinators.test matcher-combinators.test
[status-im.constants :as constants]
[status-im.contexts.wallet.db :as db]
[status-im.contexts.wallet.events :as events] [status-im.contexts.wallet.events :as events]
[status-im.contexts.wallet.events.collectibles :as collectibles])) [status-im.contexts.wallet.events.collectibles :as collectibles]))
@ -73,3 +75,46 @@
effects (collectibles/store-last-collectible-details {:db db} [last-collectible]) effects (collectibles/store-last-collectible-details {:db db} [last-collectible])
result-db (:db effects)] result-db (:db effects)]
(is (match? result-db expected-db))))) (is (match? result-db expected-db)))))
(deftest reset-selected-networks
(testing "reset-selected-networks"
(let [db {:wallet {}}
expected-db {:wallet db/defaults}
effects (events/reset-selected-networks {:db db})
result-db (:db effects)]
(is (match? result-db expected-db)))))
(deftest update-selected-networks
(testing "update-selected-networks"
(let [db {:wallet {:ui {:network-filter {:selected-networks
#{constants/optimism-network-name}
:selector-state :changed}}}}
network-name constants/arbitrum-network-name
expected-db {:wallet {:ui {:network-filter {:selected-networks
#{constants/optimism-network-name
network-name}
:selector-state :changed}}}}
props [network-name]
effects (events/update-selected-networks {:db db} props)
result-db (:db effects)]
(is (match? result-db expected-db))))
(testing "update-selected-networks > if all networks is already selected, update to incoming network"
(let [db {:wallet db/defaults}
network-name constants/arbitrum-network-name
expected-db {:wallet {:ui {:network-filter {:selected-networks #{network-name}
:selector-state :changed}}}}
props [network-name]
effects (events/update-selected-networks {:db db} props)
result-db (:db effects)]
(is (match? result-db expected-db))))
(testing "update-selected-networks > reset on removing last network"
(let [db {:wallet {:ui {:network-filter {:selected-networks
#{constants/optimism-network-name}
:selector-state :changed}}}}
expected-fx [[:dispatch [:wallet/reset-selected-networks]]]
props [constants/optimism-network-name]
effects (events/update-selected-networks {:db db} props)
result-fx (:fx effects)]
(is (match? result-fx expected-fx)))))

View File

@ -12,7 +12,7 @@
(defn view (defn view
[] []
(let [tokens-loading? (rf/sub [:wallet/tokens-loading?]) (let [tokens-loading? (rf/sub [:wallet/tokens-loading?])
{:keys [tokens]} (rf/sub [:wallet/aggregated-tokens-and-balance])] {:keys [tokens]} (rf/sub [:wallet/aggregated-token-values-and-balance])]
(if tokens-loading? (if tokens-loading?
[quo/skeleton-list [quo/skeleton-list
{:content :assets {:content :assets

View File

@ -9,7 +9,7 @@
(defn view (defn view
[{:keys [selected-tab]}] [{:keys [selected-tab]}]
(let [collectible-list (rf/sub [:wallet/all-collectibles-list]) (let [collectible-list (rf/sub [:wallet/all-collectibles-list-in-selected-networks])
request-collectibles #(rf/dispatch request-collectibles #(rf/dispatch
[:wallet/request-collectibles-for-all-accounts {}])] [:wallet/request-collectibles-for-all-accounts {}])]
[rn/view {:style style/container} [rn/view {:style style/container}

View File

@ -6,7 +6,6 @@
[status-im.contexts.wallet.home.style :as style] [status-im.contexts.wallet.home.style :as style]
[status-im.contexts.wallet.home.tabs.view :as tabs] [status-im.contexts.wallet.home.tabs.view :as tabs]
[status-im.contexts.wallet.sheets.network-filter.view :as network-filter] [status-im.contexts.wallet.sheets.network-filter.view :as network-filter]
[status-im.feature-flags :as ff]
[utils.i18n :as i18n] [utils.i18n :as i18n]
[utils.re-frame :as rf])) [utils.re-frame :as rf]))
@ -41,18 +40,16 @@
(let [[selected-tab set-selected-tab] (rn/use-state (:id (first tabs-data))) (let [[selected-tab set-selected-tab] (rn/use-state (:id (first tabs-data)))
account-list-ref (rn/use-ref-atom nil) account-list-ref (rn/use-ref-atom nil)
tokens-loading? (rf/sub [:wallet/tokens-loading?]) tokens-loading? (rf/sub [:wallet/tokens-loading?])
networks (rf/sub [:wallet/network-details]) networks (rf/sub [:wallet/selected-network-details])
account-cards-data (rf/sub [:wallet/account-cards-data]) account-cards-data (rf/sub [:wallet/account-cards-data])
cards (conj account-cards-data (new-account-card-data)) cards (conj account-cards-data (new-account-card-data))
{:keys [formatted-balance]} (rf/sub [:wallet/aggregated-token-values-and-balance])]
{:keys [formatted-balance]} (rf/sub [:wallet/aggregated-tokens-and-balance])]
(rn/use-effect (fn [] (rn/use-effect (fn []
(when (and @account-list-ref (pos? (count cards))) (when (and @account-list-ref (pos? (count cards)))
(.scrollToOffset ^js @account-list-ref (.scrollToOffset ^js @account-list-ref
#js #js
{:animated true {:animated true
:offset 0} :offset 0})))
)))
[(count cards)]) [(count cards)])
[rn/view {:style (style/home-container)} [rn/view {:style (style/home-container)}
[common.top-nav/view] [common.top-nav/view]
@ -63,10 +60,7 @@
:metrics :none :metrics :none
:balance formatted-balance :balance formatted-balance
:networks networks :networks networks
:dropdown-on-press #(ff/alert ::ff/wallet.network-filter :dropdown-on-press #(rf/dispatch [:show-bottom-sheet {:content network-filter/view}])}]]
(fn []
(rf/dispatch [:show-bottom-sheet
{:content network-filter/view}])))}]]
[quo/wallet-graph {:time-frame :empty}] [quo/wallet-graph {:time-frame :empty}]
[rn/flat-list [rn/flat-list
{:ref #(reset! account-list-ref %) {:ref #(reset! account-list-ref %)

View File

@ -53,12 +53,16 @@
:wallet/select-send-address :wallet/select-send-address
(fn [{:keys [db]} [{:keys [address recipient stack-id start-flow?]}]] (fn [{:keys [db]} [{:keys [address recipient stack-id start-flow?]}]]
(let [[prefix to-address] (utils/split-prefix-and-address address) (let [[prefix to-address] (utils/split-prefix-and-address address)
test-net? (get-in db [:profile/profile :test-networks-enabled?]) testnet-enabled? (get-in db [:profile/profile :test-networks-enabled?])
goerli-enabled? (get-in db [:profile/profile :is-goerli-enabled?]) goerli-enabled? (get-in db [:profile/profile :is-goerli-enabled?])
prefix-seq (string/split prefix #":") prefix-seq (string/split prefix #":")
selected-networks (->> prefix-seq selected-networks (->> prefix-seq
(remove string/blank?) (remove string/blank?)
(mapv #(utils/short-name->id (keyword %) test-net? goerli-enabled?)))] (mapv
#(utils/network->chain-id
{:network %
:testnet-enabled? testnet-enabled?
:goerli-enabled? goerli-enabled?})))]
{:db (-> db {:db (-> db
(assoc-in [:wallet :ui :send :recipient] (or recipient address)) (assoc-in [:wallet :ui :send :recipient] (or recipient address))
(assoc-in [:wallet :ui :send :to-address] to-address) (assoc-in [:wallet :ui :send :to-address] to-address)

View File

@ -12,9 +12,9 @@
(def sub-mocks (def sub-mocks
{:profile/profile {:currency :usd} {:profile/profile {:currency :usd}
:wallet/network-details [{:source 525 :wallet/selected-network-details [{:source 525
:short-name "eth" :short-name "eth"
:network-name :ethereum :network-name :mainnet
:chain-id 1 :chain-id 1
:related-chain-id 5}] :related-chain-id 5}]
:wallet/current-viewing-account {:path "m/44'/60'/0'/0/1" :wallet/current-viewing-account {:path "m/44'/60'/0'/0/1"
@ -30,7 +30,7 @@
:color :purple :color :purple
:hidden false :hidden false
:prod-preferred-chain-ids #{1 10 42161} :prod-preferred-chain-ids #{1 10 42161}
:network-preferences-names #{:ethereum :arbitrum :network-preferences-names #{:mainnet :arbitrum
:optimism} :optimism}
:position 1 :position 1
:clock 1698945829328 :clock 1698945829328

View File

@ -236,9 +236,10 @@
(utils/get-standard-crypto-format native-token (utils/get-standard-crypto-format native-token
fee-in-native-token)) fee-in-native-token))
fee-in-fiat (when-not confirm-disabled? fee-in-fiat (when-not confirm-disabled?
(utils/token-fiat-value fiat-currency (utils/calculate-token-fiat-value
fee-in-native-token {:currency fiat-currency
native-token)) :balance fee-in-native-token
:token native-token}))
currency-symbol (rf/sub [:profile/currency-symbol]) currency-symbol (rf/sub [:profile/currency-symbol])
fee-formatted (when fee-in-fiat fee-formatted (when fee-in-fiat
(utils/get-standard-fiat-format fee-in-crypto-formatted (utils/get-standard-fiat-format fee-in-crypto-formatted

View File

@ -2,21 +2,12 @@
(:require (:require
[quo.core :as quo] [quo.core :as quo]
[quo.theme :as quo.theme] [quo.theme :as quo.theme]
[react-native.gesture :as gesture] [react-native.core :as rn]
[status-im.common.resources :as resources] [status-im.common.resources :as resources]
[status-im.contexts.wallet.send.select-address.tabs.style :as style] [status-im.contexts.wallet.send.select-address.tabs.style :as style]
[utils.i18n :as i18n] [utils.i18n :as i18n]
[utils.re-frame :as rf])) [utils.re-frame :as rf]))
(defn- render-account-item
[{:keys [color address] :as account}]
[quo/account-item
{:account-props (assoc account :customization-color color)
:on-press #(rf/dispatch [:wallet/select-send-address
{:address address
:recipient account
:stack-id :screen/wallet.select-address}])}])
(defn my-accounts (defn my-accounts
[theme] [theme]
(let [other-accounts (rf/sub [:wallet/accounts-without-current-viewing-account])] (let [other-accounts (rf/sub [:wallet/accounts-without-current-viewing-account])]
@ -26,11 +17,15 @@
:description (i18n/label :t/here-is-a-cat-in-a-box-instead) :description (i18n/label :t/here-is-a-cat-in-a-box-instead)
:image (resources/get-themed-image :cat-in-box theme) :image (resources/get-themed-image :cat-in-box theme)
:container-style style/empty-container-style}] :container-style style/empty-container-style}]
[gesture/flat-list (into [rn/view {:style style/my-accounts-container}]
{:data other-accounts (map (fn [{:keys [color address] :as account}]
:render-fn render-account-item [quo/account-item
:content-container-style style/my-accounts-container {:account-props (assoc account :customization-color color)
:shows-vertical-scroll-indicator false}]))) :on-press #(rf/dispatch [:wallet/select-send-address
{:address address
:recipient account
:stack-id :screen/wallet.select-address}])}]))
other-accounts))))
(defn view-internal (defn view-internal
[{:keys [selected-tab theme]}] [{:keys [selected-tab theme]}]

View File

@ -1,54 +1,48 @@
(ns status-im.contexts.wallet.sheets.network-filter.view (ns status-im.contexts.wallet.sheets.network-filter.view
(:require (:require
[quo.core :as quo] [quo.core :as quo]
[reagent.core :as reagent]
[status-im.constants :as constants]
[status-im.contexts.wallet.common.utils :as utils] [status-im.contexts.wallet.common.utils :as utils]
[utils.i18n :as i18n] [utils.i18n :as i18n]
[utils.re-frame :as rf])) [utils.re-frame :as rf]))
(defn view (defn view
[] []
(let [state (reagent/atom :default) (let [selected-networks (rf/sub [:wallet/selected-networks])
networks-selected (reagent/atom #{}) selector-state (rf/sub [:wallet/network-filter-selector-state])
toggle-network (fn [network-name] color (rf/sub [:profile/customization-color])
(reset! state :changed)
(if (contains? @networks-selected
network-name)
(swap! networks-selected disj
network-name)
(swap! networks-selected conj
network-name)))
get-networks (fn []
(if (= @state :default)
constants/default-network-names
@networks-selected))]
(fn []
(let [color (rf/sub [:profile/customization-color])
network-details (rf/sub [:wallet/network-details]) network-details (rf/sub [:wallet/network-details])
viewing-account? (rf/sub [:wallet/viewing-account?])
balance-per-chain (if viewing-account?
(rf/sub [:wallet/current-viewing-account-fiat-balance-per-chain])
(rf/sub [:wallet/aggregated-fiat-balance-per-chain]))
mainnet (first network-details) mainnet (first network-details)
layer-2-networks (rest network-details)] layer-2-networks (rest network-details)]
[:<> [:<>
[quo/drawer-top {:title (i18n/label :t/select-networks)}] [quo/drawer-top {:title (i18n/label :t/select-networks)}]
[quo/category [quo/category
{:list-type :settings {:list-type :settings
:data [(utils/make-network-item mainnet :data [(utils/make-network-item
{:state @state {:state selector-state
:title (i18n/label :t/mainnet) :network-name (:network-name mainnet)
:color color :color color
:networks (get-networks) :networks selected-networks
:on-change #(toggle-network (:network-name :label-props (get balance-per-chain (:chain-id mainnet))
mainnet)) :on-change #(rf/dispatch
:label-props "$0.00"})]}] [:wallet/update-selected-networks
(:network-name
mainnet)])})]}]
[quo/category [quo/category
{:list-type :settings {:list-type :settings
:label (i18n/label :t/layer-2) :label (i18n/label :t/layer-2)
:data (mapv (fn [network] :data (mapv (fn [network]
(utils/make-network-item network (utils/make-network-item
{:state @state {:state selector-state
:network-name (:network-name network)
:color color :color color
:networks (get-networks) :networks selected-networks
:on-change #(toggle-network (:network-name :label-props (get balance-per-chain (:chain-id network))
network)) :on-change #(rf/dispatch
:label-props "$0.00"})) [:wallet/update-selected-networks
layer-2-networks)}]])))) (:network-name
network)])}))
layer-2-networks)}]]))

View File

@ -4,31 +4,37 @@
[quo.theme :as quo.theme] [quo.theme :as quo.theme]
[react-native.blur :as blur] [react-native.blur :as blur]
[reagent.core :as reagent] [reagent.core :as reagent]
[status-im.constants :as constants]
[status-im.contexts.wallet.common.utils :as utils] [status-im.contexts.wallet.common.utils :as utils]
[status-im.contexts.wallet.sheets.network-preferences.style :as style] [status-im.contexts.wallet.sheets.network-preferences.style :as style]
[utils.i18n :as i18n] [utils.i18n :as i18n]
[utils.re-frame :as rf])) [utils.re-frame :as rf]))
(defn- view-internal (defn- view-internal
[{:keys [selected-networks watch-only?]}] [{:keys [selected-networks account watch-only?]}]
(let [state (reagent/atom :default) (let [state (reagent/atom :default)
{:keys [color address {:keys [color address
network-preferences-names]} (rf/sub [:wallet/current-viewing-account]) network-preferences-names]} (or account (rf/sub [:wallet/current-viewing-account]))
initial-network-preferences-names (or selected-networks network-preferences-names) initial-network-preferences-names (or selected-networks network-preferences-names)
network-preferences-names-state (reagent/atom #{}) network-preferences-names-state (reagent/atom #{})
toggle-network (fn [network-name] toggle-network (fn [network-name]
(reset! state :changed) (reset! state :changed)
(if (contains? @network-preferences-names-state (let [contains-network? (contains?
@network-preferences-names-state
network-name) network-name)
(swap! network-preferences-names-state disj update-fn (if contains-network? disj conj)
network-name) networks-count (count
(swap! network-preferences-names-state conj @network-preferences-names-state)]
network-name))) (if (and (= networks-count 1) contains-network?)
(reset! network-preferences-names-state
(set constants/default-network-names))
(swap! network-preferences-names-state update-fn
network-name))))
get-current-preferences-names (fn [] get-current-preferences-names (fn []
(if (= @state :default) (if (= @state :default)
initial-network-preferences-names initial-network-preferences-names
@network-preferences-names-state))] @network-preferences-names-state))]
(fn [{:keys [on-save blur? theme]}] (fn [{:keys [on-save blur? theme button-label]}]
(let [network-details (rf/sub [:wallet/network-details]) (let [network-details (rf/sub [:wallet/network-details])
mainnet (first network-details) mainnet (first network-details)
layer-2-networks (rest network-details) layer-2-networks (rest network-details)
@ -70,9 +76,8 @@
[quo/category [quo/category
{:list-type :settings {:list-type :settings
:blur? blur? :blur? blur?
:data [(utils/make-network-item mainnet :data [(utils/make-network-item {:state @state
{:state @state :network-name (:network-name mainnet)
:title (i18n/label :t/mainnet)
:color color :color color
:blur? blur? :blur? blur?
:networks (get-current-preferences-names) :networks (get-current-preferences-names)
@ -83,8 +88,8 @@
:blur? blur? :blur? blur?
:label (i18n/label :t/layer-2) :label (i18n/label :t/layer-2)
:data (mapv (fn [network] :data (mapv (fn [network]
(utils/make-network-item network (utils/make-network-item {:state @state
{:state @state :network-name (:network-name network)
:color color :color color
:blur? blur? :blur? blur?
:networks (get-current-preferences-names) :networks (get-current-preferences-names)
@ -93,7 +98,8 @@
layer-2-networks)}] layer-2-networks)}]
[quo/bottom-actions [quo/bottom-actions
{:actions :one-action {:actions :one-action
:button-one-label (i18n/label :t/display) :blur? blur?
:button-one-label (or button-label (i18n/label :t/update))
:button-one-props {:disabled? (= @state :default) :button-one-props {:disabled? (= @state :default)
:on-press (fn [] :on-press (fn []
(let [chain-ids (map :chain-id current-networks)] (let [chain-ids (map :chain-id current-networks)]

View File

@ -2,7 +2,8 @@
(:require (:require
[legacy.status-im.fleet.core :as fleet] [legacy.status-im.fleet.core :as fleet]
[react-native.core :as rn] [react-native.core :as rn]
[status-im.contexts.shell.activity-center.events :as activity-center])) [status-im.contexts.shell.activity-center.events :as activity-center]
[status-im.contexts.wallet.db :as wallet]))
;; initial state of app-db ;; initial state of app-db
(def app-db (def app-db
@ -18,6 +19,7 @@
:sync-state :done :sync-state :done
:link-previews-whitelist [] :link-previews-whitelist []
:app-state "active" :app-state "active"
:wallet wallet/defaults
:peers-count 0 :peers-count 0
:node-info {} :node-info {}
:peers-summary [] :peers-summary []

View File

@ -13,7 +13,6 @@
{::wallet.bridge-token (enabled-in-env? :FLAG_BRIDGE_TOKEN_ENABLED) {::wallet.bridge-token (enabled-in-env? :FLAG_BRIDGE_TOKEN_ENABLED)
::wallet.edit-derivation-path (enabled-in-env? :FLAG_EDIT_DERIVATION_PATH) ::wallet.edit-derivation-path (enabled-in-env? :FLAG_EDIT_DERIVATION_PATH)
::wallet.remove-account (enabled-in-env? :FLAG_REMOVE_ACCOUNT_ENABLED) ::wallet.remove-account (enabled-in-env? :FLAG_REMOVE_ACCOUNT_ENABLED)
::wallet.network-filter (enabled-in-env? :FLAG_NETWORK_FILTER_ENABLED)
::community.edit-account-selection (enabled-in-env? :FLAG_EDIT_ACCOUNT_SELECTION_ENABLED)})) ::community.edit-account-selection (enabled-in-env? :FLAG_EDIT_ACCOUNT_SELECTION_ENABLED)}))
(defn feature-flags [] @feature-flags-config) (defn feature-flags [] @feature-flags-config)

View File

@ -3,6 +3,10 @@
[clojure.string :as string] [clojure.string :as string]
[re-frame.core :as re-frame])) [re-frame.core :as re-frame]))
(defn- filter-collectibles-in-chains
[collectibles chain-ids]
(filter #(contains? chain-ids (get-in % [:id :contract-id :chain-id])) collectibles))
(defn- svg-animation? (defn- svg-animation?
[url media-type] [url media-type]
(and (not (string/blank? url)) (and (not (string/blank? url))
@ -44,6 +48,13 @@
(fn [current-account] (fn [current-account]
(-> current-account :collectibles add-collectibles-preview-url))) (-> current-account :collectibles add-collectibles-preview-url)))
(re-frame/reg-sub
:wallet/current-viewing-account-collectibles-in-selected-networks
:<- [:wallet/current-viewing-account-collectibles]
:<- [:wallet/selected-networks->chain-ids]
(fn [[collectibles chain-ids]]
(filter-collectibles-in-chains collectibles chain-ids)))
(re-frame/reg-sub (re-frame/reg-sub
:wallet/all-collectibles-list :wallet/all-collectibles-list
:<- [:wallet] :<- [:wallet]
@ -61,6 +72,13 @@
(remove nil?) (remove nil?)
(add-collectibles-preview-url))))) (add-collectibles-preview-url)))))
(re-frame/reg-sub
:wallet/all-collectibles-list-in-selected-networks
:<- [:wallet/all-collectibles-list]
:<- [:wallet/selected-networks->chain-ids]
(fn [[all-collectibles chain-ids]]
(filter-collectibles-in-chains all-collectibles chain-ids)))
(re-frame/reg-sub (re-frame/reg-sub
:wallet/current-viewing-account-collectibles-filtered :wallet/current-viewing-account-collectibles-filtered
:<- [:wallet/current-viewing-account-collectibles] :<- [:wallet/current-viewing-account-collectibles]

View File

@ -35,17 +35,17 @@
(defn get-network-details (defn get-network-details
[chain-id] [chain-id]
(case chain-id (condp contains? chain-id
(constants/ethereum-mainnet-chain-id constants/ethereum-goerli-chain-id #{constants/ethereum-mainnet-chain-id constants/ethereum-goerli-chain-id
constants/ethereum-sepolia-chain-id) constants/ethereum-sepolia-chain-id}
mainnet-network-details mainnet-network-details
(constants/arbitrum-mainnet-chain-id constants/arbitrum-goerli-chain-id #{constants/arbitrum-mainnet-chain-id constants/arbitrum-goerli-chain-id
constants/arbitrum-sepolia-chain-id) constants/arbitrum-sepolia-chain-id}
arbitrum-network-details arbitrum-network-details
(constants/optimism-mainnet-chain-id constants/optimism-goerli-chain-id #{constants/optimism-mainnet-chain-id constants/optimism-goerli-chain-id
constants/optimism-sepolia-chain-id) constants/optimism-sepolia-chain-id}
optimism-network-details optimism-network-details
nil)) nil))
@ -55,13 +55,12 @@
:<- [:wallet/networks-by-mode] :<- [:wallet/networks-by-mode]
(fn [networks] (fn [networks]
(->> networks (->> networks
(keep (map
(fn [{:keys [chain-id related-chain-id layer test?]}] (fn [{:keys [chain-id related-chain-id layer]}]
(let [network-details (get-network-details (if test? related-chain-id chain-id))] (assoc (get-network-details chain-id)
(assoc network-details
:chain-id chain-id :chain-id chain-id
:related-chain-id related-chain-id :related-chain-id related-chain-id
:layer layer)))) :layer layer)))
(sort-by (juxt :layer :short-name))))) (sort-by (juxt :layer :short-name)))))
(re-frame/reg-sub (re-frame/reg-sub
@ -69,3 +68,12 @@
:<- [:wallet/network-details] :<- [:wallet/network-details]
(fn [networks [_ chain-id]] (fn [networks [_ chain-id]]
(some #(when (= chain-id (:chain-id %)) %) networks))) (some #(when (= chain-id (:chain-id %)) %) networks)))
(re-frame/reg-sub
:wallet/selected-network-details
:<- [:wallet/network-details]
:<- [:wallet/selected-networks]
(fn [[network-details selected-networks]]
(filter
#(contains? selected-networks (:network-name %))
network-details)))

View File

@ -44,11 +44,32 @@
:<- [:wallet/ui] :<- [:wallet/ui]
:-> :create-account) :-> :create-account)
(rf/reg-sub
:wallet/network-filter
:<- [:wallet/ui]
:-> :network-filter)
(rf/reg-sub
:wallet/selected-networks
:<- [:wallet/network-filter]
:-> :selected-networks)
(rf/reg-sub
:wallet/network-filter-selector-state
:<- [:wallet/network-filter]
:-> :selector-state)
(rf/reg-sub (rf/reg-sub
:wallet/current-viewing-account-address :wallet/current-viewing-account-address
:<- [:wallet] :<- [:wallet]
:-> :current-viewing-account-address) :-> :current-viewing-account-address)
(rf/reg-sub
:wallet/viewing-account?
:<- [:wallet/current-viewing-account-address]
(fn [address]
(boolean address)))
(rf/reg-sub (rf/reg-sub
:wallet/wallet-send-to-address :wallet/wallet-send-to-address
:<- [:wallet/wallet-send] :<- [:wallet/wallet-send]
@ -104,6 +125,18 @@
:<- [:wallet/create-account] :<- [:wallet/create-account]
:-> :selected-keypair-uid) :-> :selected-keypair-uid)
(rf/reg-sub
:wallet/selected-networks->chain-ids
:<- [:wallet/selected-networks]
:<- [:profile/test-networks-enabled?]
:<- [:profile/is-goerli-enabled?]
(fn [[selected-networks testnet-enabled? goerli-enabled?]]
(set (map #(utils/network->chain-id
{:network %
:testnet-enabled? testnet-enabled?
:goerli-enabled? goerli-enabled?})
selected-networks))))
(rf/reg-sub (rf/reg-sub
:wallet/accounts :wallet/accounts
:<- [:wallet] :<- [:wallet]
@ -131,17 +164,21 @@
set)) set))
(rf/reg-sub (rf/reg-sub
:wallet/balances :wallet/balances-in-selected-networks
:<- [:wallet/accounts] :<- [:wallet/accounts]
:<- [:profile/currency] :<- [:profile/currency]
(fn [[accounts currency]] :<- [:wallet/selected-networks->chain-ids]
(fn [[accounts currency chain-ids]]
(zipmap (map :address accounts) (zipmap (map :address accounts)
(map #(utils/calculate-balance-for-account currency %) accounts)))) (map #(utils/calculate-balance-from-tokens {:currency currency
:tokens (:tokens %)
:chain-ids chain-ids})
accounts))))
(rf/reg-sub (rf/reg-sub
:wallet/account-cards-data :wallet/account-cards-data
:<- [:wallet/accounts] :<- [:wallet/accounts]
:<- [:wallet/balances] :<- [:wallet/balances-in-selected-networks]
:<- [:wallet/tokens-loading?] :<- [:wallet/tokens-loading?]
:<- [:profile/currency-symbol] :<- [:profile/currency-symbol]
(fn [[accounts balances tokens-loading? currency-symbol]] (fn [[accounts balances tokens-loading? currency-symbol]]
@ -158,7 +195,7 @@
:wallet/current-viewing-account :wallet/current-viewing-account
:<- [:wallet/accounts] :<- [:wallet/accounts]
:<- [:wallet/current-viewing-account-address] :<- [:wallet/current-viewing-account-address]
:<- [:wallet/balances] :<- [:wallet/balances-in-selected-networks]
:<- [:profile/currency-symbol] :<- [:profile/currency-symbol]
(fn [[accounts current-viewing-account-address balances currency-symbol]] (fn [[accounts current-viewing-account-address balances currency-symbol]]
(let [balance (get balances current-viewing-account-address) (let [balance (get balances current-viewing-account-address)
@ -169,15 +206,21 @@
:formatted-balance formatted-balance))))) :formatted-balance formatted-balance)))))
(rf/reg-sub (rf/reg-sub
:wallet/tokens-filtered :wallet/current-viewing-account-tokens-in-selected-networks
:<- [:wallet/current-viewing-account]
:<- [:wallet/selected-networks->chain-ids]
(fn [[{:keys [tokens]} chain-ids]]
(utils/filter-tokens-in-chains tokens chain-ids)))
(rf/reg-sub
:wallet/current-viewing-account-tokens-filtered
:<- [:wallet/current-viewing-account] :<- [:wallet/current-viewing-account]
:<- [:wallet/network-details] :<- [:wallet/network-details]
(fn [[account networks] [_ query]] (fn [[account networks] [_ query]]
(let [tokens (map (fn [token] (let [tokens (map (fn [token]
(assoc token (assoc token
:networks (utils/network-list token networks) :networks (utils/network-list token networks)
:total-balance (utils/total-token-units-in-all-chains token) :total-balance (utils/calculate-total-token-balance token)))
:total-balance-fiat (utils/calculate-balance-for-token token)))
(:tokens account)) (:tokens account))
sorted-tokens (sort-by :name compare tokens) sorted-tokens (sort-by :name compare tokens)
filtered-tokens (filter #(or (string/starts-with? (string/lower-case (:name %)) filtered-tokens (filter #(or (string/starts-with? (string/lower-case (:name %))
@ -195,8 +238,7 @@
(let [tokens (map (fn [token] (let [tokens (map (fn [token]
(assoc token (assoc token
:networks (utils/network-list token networks) :networks (utils/network-list token networks)
:total-balance (utils/total-token-units-in-all-chains token) :total-balance (utils/calculate-total-token-balance token)))
:total-balance-fiat (utils/calculate-balance-for-token token)))
(:tokens account)) (:tokens account))
token (first (filter #(= (string/lower-case (:symbol %)) token (first (filter #(= (string/lower-case (:symbol %))
(string/lower-case token-symbol)) (string/lower-case token-symbol))
@ -214,14 +256,15 @@
:wallet/accounts-without-watched-accounts :wallet/accounts-without-watched-accounts
:<- [:wallet/accounts-with-customization-color] :<- [:wallet/accounts-with-customization-color]
(fn [accounts] (fn [accounts]
(remove #(:watch-only? %) accounts))) (remove :watch-only? accounts)))
(rf/reg-sub (rf/reg-sub
:wallet/account-token-values :wallet/current-viewing-account-token-values
:<- [:wallet/current-viewing-account] :<- [:wallet/current-viewing-account]
:<- [:wallet/current-viewing-account-tokens-in-selected-networks]
:<- [:profile/currency] :<- [:profile/currency]
:<- [:profile/currency-symbol] :<- [:profile/currency-symbol]
(fn [[{:keys [tokens color]} currency currency-symbol]] (fn [[{:keys [color]} tokens currency currency-symbol]]
(mapv #(utils/calculate-token-value {:token % (mapv #(utils/calculate-token-value {:token %
:color color :color color
:currency currency :currency currency
@ -235,8 +278,15 @@
(utils/aggregate-tokens-for-all-accounts accounts))) (utils/aggregate-tokens-for-all-accounts accounts)))
(rf/reg-sub (rf/reg-sub
:wallet/aggregated-tokens-and-balance :wallet/aggregated-tokens-in-selected-networks
:<- [:wallet/aggregated-tokens] :<- [:wallet/aggregated-tokens]
:<- [:wallet/selected-networks->chain-ids]
(fn [[aggregated-tokens chain-ids]]
(utils/filter-tokens-in-chains aggregated-tokens chain-ids)))
(rf/reg-sub
:wallet/aggregated-token-values-and-balance
:<- [:wallet/aggregated-tokens-in-selected-networks]
:<- [:profile/customization-color] :<- [:profile/customization-color]
:<- [:profile/currency] :<- [:profile/currency]
:<- [:profile/currency-symbol] :<- [:profile/currency-symbol]
@ -287,3 +337,25 @@
:wallet/valid-ens-or-address? :wallet/valid-ens-or-address?
:<- [:wallet/search-address] :<- [:wallet/search-address]
:-> :valid-ens-or-address?) :-> :valid-ens-or-address?)
(rf/reg-sub
:wallet/aggregated-fiat-balance-per-chain
:<- [:wallet/aggregated-tokens]
:<- [:profile/currency]
:<- [:profile/currency-symbol]
(fn [[aggregated-tokens currency currency-symbol]]
(utils/calculate-balances-per-chain
{:tokens aggregated-tokens
:currency currency
:currency-symbol currency-symbol})))
(rf/reg-sub
:wallet/current-viewing-account-fiat-balance-per-chain
:<- [:wallet/current-viewing-account]
:<- [:profile/currency]
:<- [:profile/currency-symbol]
(fn [[{:keys [tokens]} currency currency-symbol]]
(utils/calculate-balances-per-chain
{:tokens tokens
:currency currency
:currency-symbol currency-symbol})))

View File

@ -1,6 +1,9 @@
(ns status-im.subs.wallet.wallet-test (ns status-im.subs.wallet.wallet-test
(:require [cljs.test :refer [is testing use-fixtures]] (:require
[cljs.test :refer [is testing use-fixtures]]
[re-frame.db :as rf-db] [re-frame.db :as rf-db]
[status-im.constants :as constants]
[status-im.contexts.wallet.db :as db]
[status-im.subs.root] [status-im.subs.root]
[test-helpers.unit :as h] [test-helpers.unit :as h]
[utils.money :as money] [utils.money :as money]
@ -13,47 +16,75 @@
[{:decimals 1 [{:decimals 1
:symbol "ETH" :symbol "ETH"
:name "Ether" :name "Ether"
:balances-per-chain {1 {:raw-balance (money/bignumber "20") :has-error false} :balances-per-chain {constants/ethereum-mainnet-chain-id {:raw-balance (money/bignumber "20")
2 {:raw-balance (money/bignumber "10") :has-error false}} :has-error false}
constants/optimism-mainnet-chain-id {:raw-balance (money/bignumber "10")
:has-error false}}
:market-values-per-currency {:usd {:price 1000}}} :market-values-per-currency {:usd {:price 1000}}}
{:decimals 2 {:decimals 2
:symbol "DAI" :symbol "DAI"
:name "Dai Stablecoin" :name "Dai Stablecoin"
:balances-per-chain {1 {:raw-balance (money/bignumber "100") :has-error false} :balances-per-chain {constants/ethereum-mainnet-chain-id {:raw-balance (money/bignumber
2 {:raw-balance (money/bignumber "150") :has-error false} "100")
3 {:raw-balance nil :has-error false}} :has-error false}
constants/optimism-mainnet-chain-id {:raw-balance (money/bignumber
"150")
:has-error false}
constants/arbitrum-mainnet-chain-id {:raw-balance nil :has-error false}}
:market-values-per-currency {:usd {:price 100}}}]) :market-values-per-currency {:usd {:price 100}}}])
(def tokens-0x2 (def tokens-0x2
[{:decimals 3 [{:decimals 3
:symbol "ETH" :symbol "ETH"
:name "Ether" :name "Ether"
:balances-per-chain {1 {:raw-balance (money/bignumber "2500") :has-error false} :balances-per-chain {constants/ethereum-mainnet-chain-id {:raw-balance (money/bignumber
2 {:raw-balance (money/bignumber "3000") :has-error false} "2500")
3 {:raw-balance (money/bignumber "<nil>") :has-error false}} :has-error false}
constants/optimism-mainnet-chain-id {:raw-balance (money/bignumber
"3000")
:has-error false}
constants/arbitrum-mainnet-chain-id {:raw-balance (money/bignumber
"<nil>")
:has-error false}}
:market-values-per-currency {:usd {:price 200}}} :market-values-per-currency {:usd {:price 200}}}
{:decimals 10 {:decimals 10
:symbol "DAI" :symbol "DAI"
:name "Dai Stablecoin" :name "Dai Stablecoin"
:balances-per-chain {1 {:raw-balance (money/bignumber "10000000000") :has-error false} :balances-per-chain {constants/ethereum-mainnet-chain-id {:raw-balance (money/bignumber
2 {:raw-balance (money/bignumber "0") :has-error false} "10000000000")
3 {:raw-balance (money/bignumber "<nil>") :has-error false}} :has-error false}
constants/optimism-mainnet-chain-id {:raw-balance (money/bignumber "0")
:has-error false}
constants/arbitrum-mainnet-chain-id {:raw-balance (money/bignumber
"<nil>")
:has-error false}}
:market-values-per-currency {:usd {:price 1000}}}]) :market-values-per-currency {:usd {:price 1000}}}])
(def tokens-0x3 (def tokens-0x3
[{:decimals 3 [{:decimals 3
:symbol "ETH" :symbol "ETH"
:name "Ether" :name "Ether"
:balances-per-chain {1 {:raw-balance (money/bignumber "5000") :has-error false} :balances-per-chain {constants/ethereum-mainnet-chain-id {:raw-balance (money/bignumber
2 {:raw-balance (money/bignumber "2000") :has-error false} "5000")
3 {:raw-balance (money/bignumber "<nil>") :has-error false}} :has-error false}
constants/optimism-mainnet-chain-id {:raw-balance (money/bignumber
"2000")
:has-error false}
constants/arbitrum-mainnet-chain-id {:raw-balance (money/bignumber
"<nil>")
:has-error false}}
:market-values-per-currency {:usd {:price 200}}} :market-values-per-currency {:usd {:price 200}}}
{:decimals 10 {:decimals 10
:symbol "DAI" :symbol "DAI"
:name "Dai Stablecoin" :name "Dai Stablecoin"
:balances-per-chain {1 {:raw-balance (money/bignumber "10000000000") :has-error false} :balances-per-chain {constants/ethereum-mainnet-chain-id {:raw-balance (money/bignumber
2 {:raw-balance (money/bignumber "0") :has-error false} "10000000000")
3 {:raw-balance (money/bignumber "<nil>") :has-error false}} :has-error false}
constants/optimism-mainnet-chain-id {:raw-balance (money/bignumber "0")
:has-error false}
constants/arbitrum-mainnet-chain-id {:raw-balance (money/bignumber
"<nil>")
:has-error false}}
:market-values-per-currency {:usd {:price 1000}}}]) :market-values-per-currency {:usd {:price 1000}}}])
(def accounts (def accounts
@ -148,10 +179,12 @@
:chain-id 10 :chain-id 10
:layer 2}]}) :layer 2}]})
(h/deftest-sub :wallet/balances (h/deftest-sub :wallet/balances-in-selected-networks
[sub-name] [sub-name]
(testing "a map: address->balance" (testing "a map: address->balance"
(swap! rf-db/app-db #(assoc-in % [:wallet :accounts] accounts)) (swap! rf-db/app-db #(-> %
(assoc :wallet db/defaults)
(assoc-in [:wallet :accounts] accounts)))
(let [result (rf/sub [sub-name]) (let [result (rf/sub [sub-name])
balance-0x1 (money/bignumber 3250) balance-0x1 (money/bignumber 3250)
balance-0x2 (money/bignumber 2100) balance-0x2 (money/bignumber 2100)
@ -166,6 +199,7 @@
(testing "returns all accounts without balance" (testing "returns all accounts without balance"
(swap! rf-db/app-db (swap! rf-db/app-db
#(-> % #(-> %
(assoc :wallet db/defaults)
(assoc-in [:wallet :accounts] accounts) (assoc-in [:wallet :accounts] accounts)
(assoc-in [:wallet :networks] network-data))) (assoc-in [:wallet :networks] network-data)))
(is (is
@ -250,6 +284,7 @@
(testing "returns current account with balance base" (testing "returns current account with balance base"
(swap! rf-db/app-db (swap! rf-db/app-db
#(-> % #(-> %
(assoc :wallet db/defaults)
(assoc-in [:wallet :accounts] accounts) (assoc-in [:wallet :accounts] accounts)
(assoc-in [:wallet :current-viewing-account-address] "0x1") (assoc-in [:wallet :current-viewing-account-address] "0x1")
(assoc-in [:wallet :networks] network-data))) (assoc-in [:wallet :networks] network-data)))
@ -462,10 +497,12 @@
(is (match? 2 (count result))) (is (match? 2 (count result)))
(is (money/equal-to (money/bignumber 7520) eth-mainnet-raw-balance))))) (is (money/equal-to (money/bignumber 7520) eth-mainnet-raw-balance)))))
(h/deftest-sub :wallet/aggregated-tokens-and-balance (h/deftest-sub :wallet/aggregated-token-values-and-balance
[sub-name] [sub-name]
(testing "returns aggregated tokens (in quo/token-value props) and balances from all accounts" (testing "returns aggregated tokens (in quo/token-value props) and balances from all accounts"
(swap! rf-db/app-db #(assoc-in % [:wallet :accounts] accounts)) (swap! rf-db/app-db #(-> %
(assoc :wallet db/defaults)
(assoc-in [:wallet :accounts] accounts)))
(let [{:keys [formatted-balance tokens]} (rf/sub [sub-name])] (let [{:keys [formatted-balance tokens]} (rf/sub [sub-name])]
(is (match? 2 (count tokens))) (is (match? 2 (count tokens)))
(is (match? "$4506.00" formatted-balance))))) (is (match? "$4506.00" formatted-balance)))))
@ -542,3 +579,99 @@
(swap! rf-db/app-db (swap! rf-db/app-db
#(assoc-in % [:wallet :ui :create-account :selected-keypair-uid] "key-uid")) #(assoc-in % [:wallet :ui :create-account :selected-keypair-uid] "key-uid"))
(is (= "key-uid" (rf/sub [sub-name]))))) (is (= "key-uid" (rf/sub [sub-name])))))
(h/deftest-sub :wallet/current-viewing-account-tokens-filtered
[sub-name]
(testing "current viewing tokens filtered"
(swap! rf-db/app-db
#(-> %
(assoc-in [:wallet :accounts] accounts)
(assoc-in [:wallet :networks] network-data)
(assoc-in [:wallet :current-viewing-account-address] "0x2")
(assoc-in [:profile/profile :currency] :usd)))
(is (match? (count (rf/sub [sub-name ""])) 2))
(is (match? (count (rf/sub [sub-name "et"])) 1))))
(h/deftest-sub :wallet/selected-networks->chain-ids
[sub-name]
(testing "selected networks -> chain-ids - All networks"
(swap! rf-db/app-db #(assoc % :wallet db/defaults))
(is
(match? (sort [constants/ethereum-mainnet-chain-id constants/arbitrum-mainnet-chain-id
constants/optimism-mainnet-chain-id])
(sort (rf/sub [sub-name])))))
(testing "selected networks -> chain-ids - specific network"
(swap! rf-db/app-db #(assoc-in %
[:wallet :ui :network-filter :selected-networks]
#{constants/optimism-network-name}))
(is
(match? (sort [constants/optimism-mainnet-chain-id])
(sort (rf/sub [sub-name]))))))
(h/deftest-sub :wallet/current-viewing-account-tokens-in-selected-networks
[sub-name]
(testing "current account tokens in selected networks"
(swap! rf-db/app-db
#(-> %
(assoc-in [:wallet :ui :network-filter :selected-networks] #{constants/arbitrum-network-name})
(assoc-in [:wallet :accounts] accounts)
(assoc-in [:wallet :current-viewing-account-address] "0x1")
(assoc-in [:wallet :networks] network-data)))
(let [result (rf/sub [sub-name])
token (nth result 1)
chains (-> token
:balances-per-chain
keys)]
(is (match? (count chains) 1))
(is (match? (first chains) constants/arbitrum-mainnet-chain-id)))))
(h/deftest-sub :wallet/aggregated-tokens-in-selected-networks
[sub-name]
(testing "aggregated tokens in selected networks"
(swap! rf-db/app-db
#(-> %
(assoc-in [:wallet :ui :network-filter :selected-networks] #{constants/optimism-network-name})
(assoc-in [:wallet :accounts] accounts)
(assoc-in [:wallet :networks] network-data)))
(let [result (rf/sub [sub-name])
token (first result)
chains (-> token
:balances-per-chain
keys)]
(is (match? (count chains) 1))
(is (match? (first chains) constants/optimism-mainnet-chain-id)))))
(h/deftest-sub :wallet/aggregated-fiat-balance-per-chain
[sub-name]
(testing "aggregated fiat balance per chain"
(swap! rf-db/app-db
#(-> %
(assoc-in [:wallet :accounts] accounts)
(assoc-in [:wallet :networks] network-data)
(assoc-in [:profile/profile :currency] :usd)))
(let [result (rf/sub [sub-name])
chains (keys result)]
(is (match? (count chains) 3))
(is (match? (get result constants/ethereum-mainnet-chain-id) "$3504.00"))
(is (match? (get result constants/optimism-mainnet-chain-id) "$1002.00")))))
(h/deftest-sub :wallet/current-viewing-account-fiat-balance-per-chain
[sub-name]
(testing "current viewing account fiat balance per chain"
(swap! rf-db/app-db
#(-> %
(assoc-in [:wallet :accounts] accounts)
(assoc-in [:wallet :networks] network-data)
(assoc-in [:wallet :current-viewing-account-address] "0x2")
(assoc-in [:profile/profile :currency] :usd)))
(let [result (rf/sub [sub-name])
chains (keys result)]
(is (match? (count chains) 3))
(is (match? (get result constants/ethereum-mainnet-chain-id) "$1500.00"))
(is (match? (get result constants/optimism-mainnet-chain-id) "$600.00"))
(is (match? (get result constants/arbitrum-mainnet-chain-id) "$0.00")))))