mirror of
https://github.com/status-im/status-react.git
synced 2025-02-04 07:06:18 +00:00
* Add `utils.money/add` version able to work with `nil`s * Store token raw-balance as big-number * Improve account balance calculations using `utils.money` existing functions * Update `:wallet/tokens-filtered` sub * Make `prettify-balance` able to work with bignumbers
This commit is contained in:
parent
f79860fb97
commit
8b919f4058
@ -93,7 +93,7 @@
|
|||||||
:end {:x 1 :y 0}}])
|
:end {:x 1 :y 0}}])
|
||||||
|
|
||||||
(defn- user-account
|
(defn- user-account
|
||||||
[]
|
[_]
|
||||||
(let [pressed? (reagent/atom false)
|
(let [pressed? (reagent/atom false)
|
||||||
on-press-in #(reset! pressed? true)
|
on-press-in #(reset! pressed? true)
|
||||||
on-press-out #(reset! pressed? false)]
|
on-press-out #(reset! pressed? false)]
|
||||||
@ -147,7 +147,7 @@
|
|||||||
[gradient-overview theme customization-color])])))))
|
[gradient-overview theme customization-color])])))))
|
||||||
|
|
||||||
(defn- add-account-view
|
(defn- add-account-view
|
||||||
[]
|
[_]
|
||||||
(let [pressed? (reagent/atom false)]
|
(let [pressed? (reagent/atom false)]
|
||||||
(fn [{:keys [on-press customization-color theme metrics?]}]
|
(fn [{:keys [on-press customization-color theme metrics?]}]
|
||||||
[rn/pressable
|
[rn/pressable
|
||||||
|
@ -10,7 +10,12 @@
|
|||||||
|
|
||||||
(defn prettify-balance
|
(defn prettify-balance
|
||||||
[balance]
|
[balance]
|
||||||
(str "$" (.toFixed (if (number? balance) balance 0) 2)))
|
(let [valid-balance? (and balance
|
||||||
|
(or (number? balance) (.-toFixed balance)))]
|
||||||
|
(as-> balance $
|
||||||
|
(if valid-balance? $ 0)
|
||||||
|
(.toFixed $ 2)
|
||||||
|
(str "$" $))))
|
||||||
|
|
||||||
(defn get-derivation-path
|
(defn get-derivation-path
|
||||||
[number-of-accounts]
|
[number-of-accounts]
|
||||||
@ -25,32 +30,42 @@
|
|||||||
(let [path (get-derivation-path number-of-accounts)]
|
(let [path (get-derivation-path number-of-accounts)]
|
||||||
(format-derivation-path path)))
|
(format-derivation-path path)))
|
||||||
|
|
||||||
|
(defn- total-raw-balance-in-all-chains
|
||||||
|
[balances-per-chain]
|
||||||
|
(->> balances-per-chain
|
||||||
|
(map (comp :raw-balance val))
|
||||||
|
(reduce money/add)))
|
||||||
|
|
||||||
|
(defn total-token-units-in-all-chains
|
||||||
|
[{:keys [balances-per-chain decimals] :as _token}]
|
||||||
|
(-> balances-per-chain
|
||||||
|
(total-raw-balance-in-all-chains)
|
||||||
|
(money/token->unit decimals)))
|
||||||
|
|
||||||
(defn calculate-raw-balance
|
(defn calculate-raw-balance
|
||||||
[raw-balance decimals]
|
[raw-balance decimals]
|
||||||
(if-let [n (utils.number/parse-int raw-balance nil)]
|
(if-let [n (utils.number/parse-int raw-balance nil)]
|
||||||
(/ n (Math/pow 10 (utils.number/parse-int decimals)))
|
(/ n (Math/pow 10 (utils.number/parse-int decimals)))
|
||||||
0))
|
0))
|
||||||
|
|
||||||
(defn total-token-value-in-all-chains
|
|
||||||
[{:keys [balances-per-chain decimals]}]
|
|
||||||
(->> balances-per-chain
|
|
||||||
(vals)
|
|
||||||
(map #(calculate-raw-balance (:raw-balance %) decimals))
|
|
||||||
(reduce +)))
|
|
||||||
|
|
||||||
(defn token-value-in-chain
|
(defn token-value-in-chain
|
||||||
[{:keys [balances-per-chain decimals]} chain-id]
|
[{:keys [balances-per-chain decimals]} chain-id]
|
||||||
(let [balance-in-chain (get balances-per-chain chain-id)]
|
(let [balance-in-chain (get balances-per-chain chain-id)]
|
||||||
(when balance-in-chain
|
(when balance-in-chain
|
||||||
(calculate-raw-balance (:raw-balance balance-in-chain) decimals))))
|
(calculate-raw-balance (:raw-balance balance-in-chain) decimals))))
|
||||||
|
|
||||||
(defn calculate-balance
|
(defn total-token-fiat-value
|
||||||
[tokens-in-account]
|
"Returns the total token fiat value taking into account all token's chains."
|
||||||
(->> tokens-in-account
|
[{:keys [market-values-per-currency] :as token}]
|
||||||
(map (fn [token]
|
(let [usd-price (-> market-values-per-currency :usd :price)
|
||||||
(* (total-token-value-in-all-chains token)
|
total-units-in-all-chains (total-token-units-in-all-chains token)]
|
||||||
(-> token :market-values-per-currency :usd :price))))
|
(money/crypto->fiat total-units-in-all-chains usd-price)))
|
||||||
(reduce +)))
|
|
||||||
|
(defn calculate-balance-for-account
|
||||||
|
[{:keys [tokens] :as _account}]
|
||||||
|
(->> tokens
|
||||||
|
(map total-token-fiat-value)
|
||||||
|
(reduce money/add)))
|
||||||
|
|
||||||
(defn network-list
|
(defn network-list
|
||||||
[{:keys [balances-per-chain]} networks]
|
[{:keys [balances-per-chain]} networks]
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
[utils.ethereum.chain :as chain]
|
[utils.ethereum.chain :as chain]
|
||||||
[utils.ethereum.eip.eip55 :as eip55]
|
[utils.ethereum.eip.eip55 :as eip55]
|
||||||
[utils.i18n :as i18n]
|
[utils.i18n :as i18n]
|
||||||
|
[utils.money :as money]
|
||||||
[utils.number]
|
[utils.number]
|
||||||
[utils.re-frame :as rf]
|
[utils.re-frame :as rf]
|
||||||
[utils.transforms :as types]))
|
[utils.transforms :as types]))
|
||||||
@ -108,9 +109,11 @@
|
|||||||
:event :wallet/get-wallet-token
|
:event :wallet/get-wallet-token
|
||||||
:params addresses})}]]]})))
|
:params addresses})}]]]})))
|
||||||
|
|
||||||
(defn- fix-chain-id-keys
|
(defn- fix-balances-per-chain
|
||||||
[token]
|
[token]
|
||||||
(update token :balances-per-chain update-keys (comp utils.number/parse-int name)))
|
(-> token
|
||||||
|
(update :balances-per-chain update-vals #(update % :raw-balance money/bignumber))
|
||||||
|
(update :balances-per-chain update-keys (comp utils.number/parse-int name))))
|
||||||
|
|
||||||
(rf/reg-event-fx
|
(rf/reg-event-fx
|
||||||
:wallet/store-wallet-token
|
:wallet/store-wallet-token
|
||||||
@ -118,7 +121,7 @@
|
|||||||
(let [tokens (-> raw-tokens-data
|
(let [tokens (-> raw-tokens-data
|
||||||
(update-keys name)
|
(update-keys name)
|
||||||
(update-vals #(cske/transform-keys csk/->kebab-case %))
|
(update-vals #(cske/transform-keys csk/->kebab-case %))
|
||||||
(update-vals #(mapv fix-chain-id-keys %)))
|
(update-vals #(mapv fix-balances-per-chain %)))
|
||||||
add-tokens (fn [stored-accounts tokens-per-account]
|
add-tokens (fn [stored-accounts tokens-per-account]
|
||||||
(reduce-kv (fn [accounts address tokens-data]
|
(reduce-kv (fn [accounts address tokens-data]
|
||||||
(if (accounts address)
|
(if (accounts address)
|
||||||
|
@ -40,7 +40,7 @@
|
|||||||
:<- [:wallet/accounts]
|
:<- [:wallet/accounts]
|
||||||
(fn [accounts]
|
(fn [accounts]
|
||||||
(zipmap (map :address accounts)
|
(zipmap (map :address accounts)
|
||||||
(map #(-> % :tokens utils/calculate-balance) accounts))))
|
(map utils/calculate-balance-for-account accounts))))
|
||||||
|
|
||||||
(rf/reg-sub
|
(rf/reg-sub
|
||||||
:wallet/account-cards-data
|
:wallet/account-cards-data
|
||||||
@ -71,21 +71,18 @@
|
|||||||
:<- [: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-value-in-all-chains token)
|
:total-balance (utils/total-token-units-in-all-chains token)
|
||||||
:total-balance-fiat (utils/calculate-balance token)))
|
:total-balance-fiat 0))
|
||||||
(:tokens account))
|
(:tokens account))
|
||||||
|
sorted-tokens (sort-by :name compare tokens)
|
||||||
sorted-tokens
|
filtered-tokens (filter #(or (string/starts-with? (string/lower-case (:name %))
|
||||||
(sort-by :name compare tokens)
|
(string/lower-case query))
|
||||||
filtered-tokens
|
(string/starts-with? (string/lower-case (:symbol %))
|
||||||
(filter #(or (string/starts-with? (string/lower-case (:name %))
|
(string/lower-case query)))
|
||||||
(string/lower-case query))
|
sorted-tokens)]
|
||||||
(string/starts-with? (string/lower-case (:symbol %))
|
|
||||||
(string/lower-case query)))
|
|
||||||
sorted-tokens)]
|
|
||||||
filtered-tokens)))
|
filtered-tokens)))
|
||||||
|
|
||||||
(rf/reg-sub
|
(rf/reg-sub
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
(ns status-im2.subs.wallet.wallet-test
|
(ns status-im2.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-im2.subs.root
|
[status-im2.subs.root]
|
||||||
[test-helpers.unit :as h]
|
[test-helpers.unit :as h]
|
||||||
|
[utils.money :as money]
|
||||||
[utils.re-frame :as rf]))
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
(use-fixtures :each
|
(use-fixtures :each
|
||||||
@ -12,30 +13,31 @@
|
|||||||
[{:decimals 1
|
[{:decimals 1
|
||||||
:symbol "ETH"
|
:symbol "ETH"
|
||||||
:name "Ether"
|
:name "Ether"
|
||||||
:balances-per-chain {1 {:raw-balance "20" :has-error false}
|
:balances-per-chain {1 {:raw-balance (money/bignumber "20") :has-error false}
|
||||||
2 {:raw-balance "10" :has-error false}}
|
2 {: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 "100" :has-error false}
|
:balances-per-chain {1 {:raw-balance (money/bignumber "100") :has-error false}
|
||||||
2 {:raw-balance "150" :has-error false}}
|
2 {:raw-balance (money/bignumber "150") :has-error false}
|
||||||
|
3 {: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 "2500" :has-error false}
|
:balances-per-chain {1 {:raw-balance (money/bignumber "2500") :has-error false}
|
||||||
2 {:raw-balance "3000" :has-error false}
|
2 {:raw-balance (money/bignumber "3000") :has-error false}
|
||||||
3 {:raw-balance "<nil>" :has-error false}}
|
3 {: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 "10000000000" :has-error false}
|
:balances-per-chain {1 {:raw-balance (money/bignumber "10000000000") :has-error false}
|
||||||
2 {:raw-balance "0" :has-error false}
|
2 {:raw-balance (money/bignumber "0") :has-error false}
|
||||||
3 {:raw-balance "<nil>" :has-error false}}
|
3 {: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
|
||||||
@ -84,9 +86,12 @@
|
|||||||
[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-in % [:wallet :accounts] accounts))
|
||||||
|
(let [result (rf/sub [sub-name])
|
||||||
|
balance-0x1 (money/bignumber 3250)
|
||||||
|
balance-0x2 (money/bignumber 2100)]
|
||||||
|
|
||||||
(is (= {"0x1" 3250 "0x2" 2100}
|
(is (money/equal-to balance-0x1 (get result "0x1")))
|
||||||
(rf/sub [sub-name])))))
|
(is (money/equal-to balance-0x2 (get result "0x2"))))))
|
||||||
|
|
||||||
(h/deftest-sub :wallet/accounts
|
(h/deftest-sub :wallet/accounts
|
||||||
[sub-name]
|
[sub-name]
|
||||||
@ -143,30 +148,32 @@
|
|||||||
#(-> %
|
#(-> %
|
||||||
(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")))
|
||||||
|
(let [result (rf/sub [sub-name])]
|
||||||
|
|
||||||
(is
|
(is
|
||||||
(= {:path "m/44'/60'/0'/0/0"
|
(= {:path "m/44'/60'/0'/0/0"
|
||||||
:emoji "😃"
|
:emoji "😃"
|
||||||
:key-uid "0x2f5ea39"
|
:key-uid "0x2f5ea39"
|
||||||
:address "0x1"
|
:address "0x1"
|
||||||
:wallet false
|
:wallet false
|
||||||
:name "Account One"
|
:name "Account One"
|
||||||
:type :generated
|
:type :generated
|
||||||
:chat false
|
:chat false
|
||||||
:test-preferred-chain-ids #{5 420 421613}
|
:test-preferred-chain-ids #{5 420 421613}
|
||||||
:color :blue
|
:color :blue
|
||||||
:hidden false
|
:hidden false
|
||||||
:prod-preferred-chain-ids #{1 10 42161}
|
:prod-preferred-chain-ids #{1 10 42161}
|
||||||
:position 0
|
:position 0
|
||||||
:clock 1698945829328
|
:clock 1698945829328
|
||||||
:created-at 1698928839000
|
:created-at 1698928839000
|
||||||
:operable "fully"
|
:operable "fully"
|
||||||
:mixedcase-address "0x7bcDfc75c431"
|
:mixedcase-address "0x7bcDfc75c431"
|
||||||
:public-key "0x04371e2d9d66b82f056bc128064"
|
:public-key "0x04371e2d9d66b82f056bc128064"
|
||||||
:removed false
|
:removed false
|
||||||
:balance 3250
|
:tokens tokens-0x1}
|
||||||
:tokens tokens-0x1}
|
(dissoc result :balance)))
|
||||||
(rf/sub [sub-name])))))
|
|
||||||
|
(is (money/equal-to (:balance result) (money/bignumber 3250))))))
|
||||||
|
|
||||||
|
|
||||||
(h/deftest-sub :wallet/addresses
|
(h/deftest-sub :wallet/addresses
|
||||||
|
@ -152,7 +152,7 @@
|
|||||||
;; E.g. for Ether, it's smallest part is wei or 10^(-18) of 1 ether
|
;; E.g. for Ether, it's smallest part is wei or 10^(-18) of 1 ether
|
||||||
;; for arbitrary ERC20 token the smallest part is 10^(-decimals) of 1 token
|
;; for arbitrary ERC20 token the smallest part is 10^(-decimals) of 1 token
|
||||||
;;
|
;;
|
||||||
;; Different tokens can have different number of allowed decimals, so it's neccessary to include the
|
;; Different tokens can have different number of allowed decimals, so it's necessary to include the
|
||||||
;; decimals parameter
|
;; decimals parameter
|
||||||
;; to get the amount scale right.
|
;; to get the amount scale right.
|
||||||
|
|
||||||
@ -205,10 +205,14 @@
|
|||||||
(with-precision 2)
|
(with-precision 2)
|
||||||
str))
|
str))
|
||||||
|
|
||||||
(defn add
|
(defn- add*
|
||||||
[bn1 n2]
|
[bn1 n2]
|
||||||
(.add ^js bn1 n2))
|
(.add ^js bn1 n2))
|
||||||
|
|
||||||
|
(def add
|
||||||
|
"Add with defaults, this version is able to receive `nil` and takes them as 0."
|
||||||
|
(fnil add* (bignumber 0) (bignumber 0)))
|
||||||
|
|
||||||
(defn mul
|
(defn mul
|
||||||
[bn1 bn2]
|
[bn1 bn2]
|
||||||
(.mul ^js bn1 bn2))
|
(.mul ^js bn1 bn2))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user