* 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}}])
|
||||
|
||||
(defn- user-account
|
||||
[]
|
||||
[_]
|
||||
(let [pressed? (reagent/atom false)
|
||||
on-press-in #(reset! pressed? true)
|
||||
on-press-out #(reset! pressed? false)]
|
||||
|
@ -147,7 +147,7 @@
|
|||
[gradient-overview theme customization-color])])))))
|
||||
|
||||
(defn- add-account-view
|
||||
[]
|
||||
[_]
|
||||
(let [pressed? (reagent/atom false)]
|
||||
(fn [{:keys [on-press customization-color theme metrics?]}]
|
||||
[rn/pressable
|
||||
|
|
|
@ -10,7 +10,12 @@
|
|||
|
||||
(defn prettify-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
|
||||
[number-of-accounts]
|
||||
|
@ -25,32 +30,42 @@
|
|||
(let [path (get-derivation-path number-of-accounts)]
|
||||
(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
|
||||
[raw-balance decimals]
|
||||
(if-let [n (utils.number/parse-int raw-balance nil)]
|
||||
(/ n (Math/pow 10 (utils.number/parse-int decimals)))
|
||||
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
|
||||
[{:keys [balances-per-chain decimals]} chain-id]
|
||||
(let [balance-in-chain (get balances-per-chain chain-id)]
|
||||
(when balance-in-chain
|
||||
(calculate-raw-balance (:raw-balance balance-in-chain) decimals))))
|
||||
|
||||
(defn calculate-balance
|
||||
[tokens-in-account]
|
||||
(->> tokens-in-account
|
||||
(map (fn [token]
|
||||
(* (total-token-value-in-all-chains token)
|
||||
(-> token :market-values-per-currency :usd :price))))
|
||||
(reduce +)))
|
||||
(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)
|
||||
total-units-in-all-chains (total-token-units-in-all-chains token)]
|
||||
(money/crypto->fiat total-units-in-all-chains usd-price)))
|
||||
|
||||
(defn calculate-balance-for-account
|
||||
[{:keys [tokens] :as _account}]
|
||||
(->> tokens
|
||||
(map total-token-fiat-value)
|
||||
(reduce money/add)))
|
||||
|
||||
(defn network-list
|
||||
[{:keys [balances-per-chain]} networks]
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
[utils.ethereum.chain :as chain]
|
||||
[utils.ethereum.eip.eip55 :as eip55]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.money :as money]
|
||||
[utils.number]
|
||||
[utils.re-frame :as rf]
|
||||
[utils.transforms :as types]))
|
||||
|
@ -108,9 +109,11 @@
|
|||
:event :wallet/get-wallet-token
|
||||
:params addresses})}]]]})))
|
||||
|
||||
(defn- fix-chain-id-keys
|
||||
(defn- fix-balances-per-chain
|
||||
[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
|
||||
:wallet/store-wallet-token
|
||||
|
@ -118,7 +121,7 @@
|
|||
(let [tokens (-> raw-tokens-data
|
||||
(update-keys name)
|
||||
(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]
|
||||
(reduce-kv (fn [accounts address tokens-data]
|
||||
(if (accounts address)
|
||||
|
|
|
@ -40,7 +40,7 @@
|
|||
:<- [:wallet/accounts]
|
||||
(fn [accounts]
|
||||
(zipmap (map :address accounts)
|
||||
(map #(-> % :tokens utils/calculate-balance) accounts))))
|
||||
(map utils/calculate-balance-for-account accounts))))
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet/account-cards-data
|
||||
|
@ -71,21 +71,18 @@
|
|||
:<- [:wallet/current-viewing-account]
|
||||
:<- [:wallet/network-details]
|
||||
(fn [[account networks] [_ query]]
|
||||
(let [tokens (map (fn [token]
|
||||
(assoc token
|
||||
:networks (utils/network-list token networks)
|
||||
:total-balance (utils/total-token-value-in-all-chains token)
|
||||
:total-balance-fiat (utils/calculate-balance token)))
|
||||
(:tokens account))
|
||||
|
||||
sorted-tokens
|
||||
(sort-by :name compare tokens)
|
||||
filtered-tokens
|
||||
(filter #(or (string/starts-with? (string/lower-case (:name %))
|
||||
(string/lower-case query))
|
||||
(string/starts-with? (string/lower-case (:symbol %))
|
||||
(string/lower-case query)))
|
||||
sorted-tokens)]
|
||||
(let [tokens (map (fn [token]
|
||||
(assoc token
|
||||
:networks (utils/network-list token networks)
|
||||
:total-balance (utils/total-token-units-in-all-chains token)
|
||||
:total-balance-fiat 0))
|
||||
(:tokens account))
|
||||
sorted-tokens (sort-by :name compare tokens)
|
||||
filtered-tokens (filter #(or (string/starts-with? (string/lower-case (:name %))
|
||||
(string/lower-case query))
|
||||
(string/starts-with? (string/lower-case (:symbol %))
|
||||
(string/lower-case query)))
|
||||
sorted-tokens)]
|
||||
filtered-tokens)))
|
||||
|
||||
(rf/reg-sub
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
(ns status-im2.subs.wallet.wallet-test
|
||||
(:require [cljs.test :refer [is testing use-fixtures]]
|
||||
[re-frame.db :as rf-db]
|
||||
status-im2.subs.root
|
||||
[status-im2.subs.root]
|
||||
[test-helpers.unit :as h]
|
||||
[utils.money :as money]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(use-fixtures :each
|
||||
|
@ -12,30 +13,31 @@
|
|||
[{:decimals 1
|
||||
:symbol "ETH"
|
||||
:name "Ether"
|
||||
:balances-per-chain {1 {:raw-balance "20" :has-error false}
|
||||
2 {:raw-balance "10" :has-error false}}
|
||||
:balances-per-chain {1 {:raw-balance (money/bignumber "20") :has-error false}
|
||||
2 {:raw-balance (money/bignumber "10") :has-error false}}
|
||||
:market-values-per-currency {:usd {:price 1000}}}
|
||||
{:decimals 2
|
||||
:symbol "DAI"
|
||||
:name "Dai Stablecoin"
|
||||
:balances-per-chain {1 {:raw-balance "100" :has-error false}
|
||||
2 {:raw-balance "150" :has-error false}}
|
||||
:balances-per-chain {1 {:raw-balance (money/bignumber "100") :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}}}])
|
||||
|
||||
(def tokens-0x2
|
||||
[{:decimals 3
|
||||
:symbol "ETH"
|
||||
:name "Ether"
|
||||
:balances-per-chain {1 {:raw-balance "2500" :has-error false}
|
||||
2 {:raw-balance "3000" :has-error false}
|
||||
3 {:raw-balance "<nil>" :has-error false}}
|
||||
:balances-per-chain {1 {:raw-balance (money/bignumber "2500") :has-error false}
|
||||
2 {:raw-balance (money/bignumber "3000") :has-error false}
|
||||
3 {:raw-balance (money/bignumber "<nil>") :has-error false}}
|
||||
:market-values-per-currency {:usd {:price 200}}}
|
||||
{:decimals 10
|
||||
:symbol "DAI"
|
||||
:name "Dai Stablecoin"
|
||||
:balances-per-chain {1 {:raw-balance "10000000000" :has-error false}
|
||||
2 {:raw-balance "0" :has-error false}
|
||||
3 {:raw-balance "<nil>" :has-error false}}
|
||||
:balances-per-chain {1 {:raw-balance (money/bignumber "10000000000") :has-error false}
|
||||
2 {:raw-balance (money/bignumber "0") :has-error false}
|
||||
3 {:raw-balance (money/bignumber "<nil>") :has-error false}}
|
||||
:market-values-per-currency {:usd {:price 1000}}}])
|
||||
|
||||
(def accounts
|
||||
|
@ -84,9 +86,12 @@
|
|||
[sub-name]
|
||||
(testing "a map: address->balance"
|
||||
(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}
|
||||
(rf/sub [sub-name])))))
|
||||
(is (money/equal-to balance-0x1 (get result "0x1")))
|
||||
(is (money/equal-to balance-0x2 (get result "0x2"))))))
|
||||
|
||||
(h/deftest-sub :wallet/accounts
|
||||
[sub-name]
|
||||
|
@ -143,30 +148,32 @@
|
|||
#(-> %
|
||||
(assoc-in [:wallet :accounts] accounts)
|
||||
(assoc-in [:wallet :current-viewing-account-address] "0x1")))
|
||||
(let [result (rf/sub [sub-name])]
|
||||
|
||||
(is
|
||||
(= {:path "m/44'/60'/0'/0/0"
|
||||
:emoji "😃"
|
||||
:key-uid "0x2f5ea39"
|
||||
:address "0x1"
|
||||
:wallet false
|
||||
:name "Account One"
|
||||
:type :generated
|
||||
:chat false
|
||||
:test-preferred-chain-ids #{5 420 421613}
|
||||
:color :blue
|
||||
:hidden false
|
||||
:prod-preferred-chain-ids #{1 10 42161}
|
||||
:position 0
|
||||
:clock 1698945829328
|
||||
:created-at 1698928839000
|
||||
:operable "fully"
|
||||
:mixedcase-address "0x7bcDfc75c431"
|
||||
:public-key "0x04371e2d9d66b82f056bc128064"
|
||||
:removed false
|
||||
:balance 3250
|
||||
:tokens tokens-0x1}
|
||||
(rf/sub [sub-name])))))
|
||||
(is
|
||||
(= {:path "m/44'/60'/0'/0/0"
|
||||
:emoji "😃"
|
||||
:key-uid "0x2f5ea39"
|
||||
:address "0x1"
|
||||
:wallet false
|
||||
:name "Account One"
|
||||
:type :generated
|
||||
:chat false
|
||||
:test-preferred-chain-ids #{5 420 421613}
|
||||
:color :blue
|
||||
:hidden false
|
||||
:prod-preferred-chain-ids #{1 10 42161}
|
||||
:position 0
|
||||
:clock 1698945829328
|
||||
:created-at 1698928839000
|
||||
:operable "fully"
|
||||
:mixedcase-address "0x7bcDfc75c431"
|
||||
:public-key "0x04371e2d9d66b82f056bc128064"
|
||||
:removed false
|
||||
:tokens tokens-0x1}
|
||||
(dissoc result :balance)))
|
||||
|
||||
(is (money/equal-to (:balance result) (money/bignumber 3250))))))
|
||||
|
||||
|
||||
(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
|
||||
;; 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
|
||||
;; to get the amount scale right.
|
||||
|
||||
|
@ -205,10 +205,14 @@
|
|||
(with-precision 2)
|
||||
str))
|
||||
|
||||
(defn add
|
||||
(defn- add*
|
||||
[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
|
||||
[bn1 bn2]
|
||||
(.mul ^js bn1 bn2))
|
||||
|
|
Loading…
Reference in New Issue