feature #6239 - showing native currency symbol differently for non-mainnet chains

Signed-off-by: Goran Jovic <goranjovic@gmail.com>
This commit is contained in:
Goran Jovic 2018-10-10 13:07:48 +02:00
parent 75ade1673b
commit 24068fe0e9
No known key found for this signature in database
GPG Key ID: D429D1A9B2EB8A8E
27 changed files with 149 additions and 86 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 836 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 836 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 836 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

@ -26,19 +26,21 @@
[status-im.ui.screens.currency-settings.subs :as currency-settings.subs]
[status-im.models.transactions :as wallet.transactions]
[status-im.ui.screens.navigation :as navigation]
status-im.chat.commands.impl.transactions.subs))
status-im.chat.commands.impl.transactions.subs
[status-im.ui.screens.wallet.utils :as wallet.utils]))
;; common `send/request` functionality
(defn- render-asset [selected-event-creator]
(fn [{:keys [name symbol amount decimals] :as asset}]
[react/touchable-highlight
{:on-press #(re-frame/dispatch (selected-event-creator (clojure.core/name symbol)))}
{:on-press #(re-frame/dispatch (selected-event-creator (wallet.utils/display-symbol asset)))}
[react/view transactions-styles/asset-container
[react/view transactions-styles/asset-main
[react/image {:source (-> asset :icon :source)
:style transactions-styles/asset-icon}]
[react/text {:style transactions-styles/asset-symbol} symbol]
[react/text {:style transactions-styles/asset-symbol}
(wallet.utils/display-symbol asset)]
[react/text {:style transactions-styles/asset-name} name]]
;;TODO(goranjovic) : temporarily disabled to fix https://github.com/status-im/status-react/issues/4963
;;until the resolution of https://github.com/status-im/status-react/issues/4972
@ -85,10 +87,11 @@
(defn personal-send-request-short-preview
[label-key {:keys [content]}]
(let [{:keys [amount asset]} (:params content)]
(let [{:keys [amount asset network]} (:params content)
token (tokens/asset-for (keyword network) (keyword asset))]
[chat-preview/text {}
(i18n/label label-key {:amount (i18n/label-number amount)
:asset asset})]))
:asset (wallet.utils/display-symbol token)})]))
(def personal-send-request-params
[{:id :asset
@ -143,9 +146,10 @@
;; because balances are only fetched for them. Revisit this decision with regard to battery/network consequences
;; if we were to update all balances.
(defn- allowed-assets [{:account/keys [account] :keys [chain]}]
(let [chain-keyword (keyword chain)
visible-tokens (get-in account [:settings :wallet :visible-tokens chain-keyword])]
(into {"ETH" 18}
(let [chain-keyword (keyword chain)
{:keys [symbol symbol-display decimals]} (tokens/native-currency chain-keyword)
visible-tokens (get-in account [:settings :wallet :visible-tokens chain-keyword])]
(into {(name (or symbol-display symbol)) decimals}
(comp (filter #(and (not (:nft? %))
(contains? visible-tokens (:symbol %))))
(map (juxt (comp name :symbol) :decimals)))
@ -208,7 +212,8 @@
(letsubs [network [:network-name]]
(let [{{:keys [amount fiat-amount tx-hash asset currency] send-network :network} :params} content
recipient-name (get-in content [:params :bot-db :public :recipient])
network-mismatch? (and (seq send-network) (not= network send-network))]
network-mismatch? (and (seq send-network) (not= network send-network))
token (tokens/asset-for (keyword send-network) (keyword asset))]
[react/view transactions-styles/command-send-message-view
[react/view
[react/view transactions-styles/command-send-amount-row
@ -220,7 +225,7 @@
"."]
[react/text {:style (transactions-styles/command-send-currency-text outgoing)
:font :default}
asset]]]]
(wallet.utils/display-symbol token)]]]]
(when (and fiat-amount
platform/mobile?)
[react/view transactions-styles/command-send-fiat-amount
@ -297,12 +302,12 @@
(let [recipient-contact (get-in db [:contacts/contacts (:current-chat-id db)])
sender-account (:account/account db)
chain (keyword (:chain db))
symbol (keyword asset)
{:keys [decimals]} (tokens/asset-for chain symbol)
{:keys [value error]} (wallet.db/parse-amount amount decimals)
next-view-id (if (:wallet-set-up-passed? sender-account)
:wallet-send-transaction-modal
:wallet-onboarding-setup)]
symbol-param (keyword asset)
{:keys [symbol decimals]} (tokens/asset-for chain symbol-param)
{:keys [value error]} (wallet.db/parse-amount amount decimals)
next-view-id (if (:wallet-set-up-passed? sender-account)
:wallet-send-transaction-modal
:wallet-onboarding-setup)]
(fx/merge cofx
{:db (-> db
(update-in [:wallet :send-transaction]

View File

@ -47,9 +47,6 @@
:console (js/require "./resources/images/contacts/console.png")})
(def assets
{:ethereum (js/require "./resources/images/assets/ethereum.png")})
(def ui
{:empty-hashtags (js/require "./resources/images/ui/empty-hashtags.png")
:empty-recent (js/require "./resources/images/ui/empty-recent.png")

View File

@ -116,7 +116,7 @@
:request :wallet.request/set-symbol
(throw (str "Unknown type: " k))))
(defn- render-token [{:keys [symbol name icon decimals amount]} type]
(defn- render-token [{:keys [symbol name icon decimals amount] :as token} type]
[list/touchable-item #(do (re-frame/dispatch [(type->handler type) symbol])
(re-frame/dispatch [:navigate-back]))
[react/view
@ -127,7 +127,7 @@
[react/text {:style styles/text-list-primary-content}
name]
[react/text {:force-uppercase? true}
(clojure.core/name symbol)]]
(wallet.utils/display-symbol token)]]
[list/item-secondary (wallet.utils/format-amount amount decimals)]]]]])
(views/defview assets [type]
@ -155,7 +155,7 @@
(views/defview asset-selector [{:keys [disabled? type symbol error]}]
(views/letsubs [balance [:balance]
network [:network]]
(let [{:keys [name icon decimals]} (tokens/asset-for (ethereum/network->chain-keyword network) symbol)]
(let [{:keys [name icon decimals] :as token} (tokens/asset-for (ethereum/network->chain-keyword network) symbol)]
(when name
[react/view
[cartouche {:disabled? disabled? :on-press #(re-frame/dispatch [:navigate-to (type->view type)])}
@ -168,7 +168,7 @@
[react/text {:style (merge styles/text-content styles/asset-label)}
name]
[react/text {:style styles/text-secondary-content}
(clojure.core/name symbol)]]
(wallet.utils/display-symbol token)]]
[react/text {:style (merge styles/text-secondary-content styles/asset-label)}
(str (wallet.utils/format-amount (get balance symbol) decimals))]]]]
(when error

View File

@ -89,7 +89,7 @@
:action #(re-frame/dispatch [:navigate-to :transactions-history])}])
(defn- render-asset [currency]
(fn [{:keys [symbol icon decimals amount]}]
(fn [{:keys [symbol symbol-display icon decimals amount] :as token}]
(let [asset-value (re-frame/subscribe [:asset-value symbol decimals (-> currency :code keyword)])]
[react/view {:style styles/asset-item-container}
[list/item
@ -103,7 +103,7 @@
[react/text {:style styles/asset-item-currency
:uppercase? true
:number-of-lines 1}
(clojure.core/name symbol)]]
(wallet.utils/display-symbol token)]]
[react/text {:style styles/asset-item-price
:uppercase? true
:number-of-lines 1}

View File

@ -20,7 +20,8 @@
[status-im.utils.ethereum.core :as ethereum]
[status-im.utils.ethereum.eip681 :as eip681]
[status-im.utils.utils :as utils]
[status-im.utils.ethereum.tokens :as tokens]))
[status-im.utils.ethereum.tokens :as tokens]
[status-im.ui.screens.wallet.utils :as wallet.utils]))
;; Request screen
@ -56,7 +57,8 @@
[bottom-buttons/bottom-buttons styles/bottom-buttons
nil ;; Force a phantom button to ensure consistency with other transaction screens which define 2 buttons
[button/button {:disabled? (or amount-error (not (and to amount)))
:on-press #(re-frame/dispatch [:wallet-send-request whisper-identity amount symbol decimals])
:on-press #(re-frame/dispatch [:wallet-send-request whisper-identity amount
(wallet.utils/display-symbol token) decimals])
:text-style {:padding-horizontal 0}
:accessibility-label :sent-request-button}
(i18n/label :t/send-request)

View File

@ -28,7 +28,8 @@
[status-im.transport.utils :as transport.utils]
[taoensso.timbre :as log]
[reagent.core :as reagent]
[status-im.ui.components.colors :as colors]))
[status-im.ui.components.colors :as colors]
[status-im.ui.screens.wallet.utils :as wallet.utils]))
(defn- toolbar [modal? title]
(let [action (if modal? actions/close-white actions/back-white)]
@ -38,7 +39,7 @@
#(actions/default-handler)))]
[toolbar/content-title {:color :white} title]]))
(defn- advanced-cartouche [{:keys [max-fee gas gas-price]}]
(defn- advanced-cartouche [native-currency {:keys [max-fee gas gas-price]}]
[react/view
[wallet.components/cartouche {:on-press #(do (re-frame/dispatch [:wallet.send/clear-gas])
(re-frame/dispatch [:navigate-to :wallet-transaction-fee]))}
@ -46,11 +47,11 @@
[react/view {:style styles/advanced-options-text-wrapper
:accessibility-label :transaction-fee-button}
[react/text {:style styles/advanced-fees-text}
(str max-fee " " (i18n/label :t/eth))]
(str max-fee " " (wallet.utils/display-symbol native-currency))]
[react/text {:style styles/advanced-fees-details-text}
(str (money/to-fixed gas) " * " (money/to-fixed (money/wei-> :gwei gas-price)) (i18n/label :t/gwei))]]]])
(defn- advanced-options [advanced? transaction scroll]
(defn- advanced-options [advanced? native-currency transaction scroll]
[react/view {:style styles/advanced-wrapper}
[react/touchable-highlight {:on-press (fn []
(re-frame/dispatch [:wallet.send/toggle-advanced (not advanced?)])
@ -63,7 +64,7 @@
:key :wallet-advanced}]
[vector-icons/icon (if advanced? :icons/up :icons/down) {:color :white}]]]]
(when advanced?
[advanced-cartouche transaction])])
[advanced-cartouche native-currency transaction])])
(defview password-input-panel [message-label spinning?]
(letsubs [account [:get-current-account]
@ -140,7 +141,9 @@
(defn- render-send-transaction-view [{:keys [modal? transaction scroll advanced? network amount-input network-status]}]
(let [{:keys [amount amount-text amount-error asset-error show-password-input? to to-name sufficient-funds?
sufficient-gas? in-progress? from-chat? symbol]} transaction
{:keys [decimals] :as token} (tokens/asset-for (ethereum/network->chain-keyword network) symbol)
chain (ethereum/network->chain-keyword network)
native-currency (tokens/native-currency chain)
{:keys [decimals] :as token} (tokens/asset-for chain symbol)
online? (= :online network-status)]
[wallet.components/simple-screen {:avoid-keyboard? (not modal?)
:status-bar-type (if modal? :modal-wallet :wallet)}
@ -170,7 +173,7 @@
:amount-text amount-text
:input-options {:on-change-text #(re-frame/dispatch [:wallet.send/set-and-validate-amount % symbol decimals])
:ref (partial reset! amount-input)}} token]
[advanced-options advanced? transaction scroll]]]
[advanced-options advanced? native-currency transaction scroll]]]
(if show-password-input?
[enter-password-buttons in-progress?
#(re-frame/dispatch [:wallet/cancel-entering-password])

View File

@ -103,9 +103,10 @@
:<- [:network]
:<- [:wallet/visible-tokens-symbols]
(fn [[network visible-tokens-symbols]]
(conj (filter #(contains? visible-tokens-symbols (:symbol %))
(tokens/sorted-tokens-for (ethereum/network->chain-keyword network)))
tokens/ethereum)))
(let [chain (ethereum/network->chain-keyword network)]
(conj (filter #(contains? visible-tokens-symbols (:symbol %))
(tokens/sorted-tokens-for (ethereum/network->chain-keyword network)))
(tokens/native-currency chain)))))
(re-frame/reg-sub :wallet/visible-assets-with-amount
:<- [:balance]

View File

@ -14,7 +14,8 @@
[status-im.ui.screens.wallet.styles :as wallet.styles]
[status-im.utils.money :as money]
[status-im.utils.ethereum.tokens :as tokens]
[status-im.utils.ethereum.core :as ethereum]))
[status-im.utils.ethereum.core :as ethereum]
[status-im.ui.screens.wallet.utils :as wallet.utils]))
(defn- toolbar [title]
[toolbar/toolbar {:style wallet.styles/toolbar}
@ -28,9 +29,11 @@
max-fee :max-fee
gas-price-edit :gas-price} [:wallet/edit]]
(let [{:keys [amount symbol]} send-transaction
gas (:value gas-edit)
gas-price (:value gas-price-edit)
{:keys [decimals]} (tokens/asset-for (ethereum/network->chain-keyword network) symbol)]
gas (:value gas-edit)
gas-price (:value gas-price-edit)
chain (ethereum/network->chain-keyword network)
native-currency (tokens/native-currency chain)
{:keys [decimals] :as token} (tokens/asset-for chain symbol)]
[components/simple-screen {:status-bar-type :modal-wallet}
[toolbar (i18n/label :t/wallet-transaction-fee)]
[react/view components.styles/flex
@ -77,12 +80,12 @@
[react/view {:accessibility-label :amount-input}
[components/cartouche-text-content
(str (money/to-fixed (money/internal->formatted amount symbol decimals)))
(name symbol)]]]
(wallet.utils/display-symbol token)]]]
[components/cartouche {:disabled? true}
(i18n/label :t/wallet-transaction-total-fee)
[react/view {:accessibility-label :total-fee-input}
[components/cartouche-text-content
(str max-fee " " (i18n/label :t/eth))]]]]
(str max-fee " " (wallet.utils/display-symbol native-currency))]]]]
[bottom-buttons/bottom-buttons styles/fee-buttons
[button/button {:on-press #(re-frame/dispatch [:wallet.send/reset-gas-default])

View File

@ -5,7 +5,9 @@
[status-im.utils.hex :as utils.hex]
[status-im.utils.money :as money]
[status-im.utils.transactions :as transactions]
[status-im.utils.ethereum.core :as ethereum]))
[status-im.utils.ethereum.core :as ethereum]
[status-im.utils.ethereum.tokens :as tokens]
[status-im.ui.screens.wallet.utils :as wallet.utils]))
(reg-sub :wallet.transactions/transactions-loading?
:<- [:wallet]
@ -92,10 +94,12 @@
:<- [:network]
(fn [[transactions current-transaction network]]
(let [{:keys [gas-used gas-price hash timestamp type] :as transaction} (get transactions current-transaction)
chain (ethereum/network->chain-keyword network)]
chain (ethereum/network->chain-keyword network)
native-currency (tokens/native-currency chain)
display-unit (wallet.utils/display-symbol native-currency)]
(when transaction
(merge transaction
{:gas-price-eth (if gas-price (money/wei->str :eth gas-price) "-")
{:gas-price-eth (if gas-price (money/wei->str :eth gas-price display-unit) "-")
:gas-price-gwei (if gas-price (money/wei->str :gwei gas-price) "-")
:date (datetime/timestamp->long-date timestamp)}
(if (= type :unsigned)
@ -106,7 +110,7 @@
:nonce (i18n/label :not-applicable)
:hash (i18n/label :not-applicable)}
{:cost (when gas-used
(money/wei->str :eth (money/fee-value gas-used gas-price)))
(money/wei->str :eth (money/fee-value gas-used gas-price) display-unit))
:url (transactions/get-transaction-details-url chain hash)}))))))
(reg-sub :wallet.transactions.details/confirmations

View File

@ -13,7 +13,8 @@
[status-im.ui.screens.wallet.transactions.styles :as styles]
[status-im.utils.money :as money]
[status-im.utils.ethereum.tokens :as tokens]
[status-im.utils.ethereum.core :as ethereum]))
[status-im.utils.ethereum.core :as ethereum]
[status-im.ui.screens.wallet.utils :as wallet.utils]))
(defn history-action [filter?]
(cond->
@ -55,7 +56,7 @@
address-accessibility-label] (if (inbound? type)
[(i18n/label :t/from) from-contact from :sender-text :sender-address-text]
[(i18n/label :t/to) to-contact to :recipient-name-text :recipient-address-text])
{:keys [decimals]} (tokens/asset-for (ethereum/network->chain-keyword network) symbol)]
{:keys [decimals] :as token} (tokens/asset-for (ethereum/network->chain-keyword network) symbol)]
[list/touchable-item #(when-not hide-details? (re-frame/dispatch [:show-transaction-details hash]))
[react/view {:accessibility-label :transaction-item}
[list/item
@ -70,7 +71,7 @@
(-> value (money/internal->formatted symbol decimals) money/to-fixed str)]
" "
[react/text {:accessibility-label :currency-text}
(clojure.string/upper-case (name symbol))]]
(wallet.utils/display-symbol token)]]
[react/text {:style styles/tx-time}
time-formatted]]
[react/view {:style styles/address-row}
@ -162,18 +163,19 @@
(-> amount (money/token->unit (:decimals token)) money/to-fixed str))
"..."))
(defn details-header [{:keys [value date type symbol token]}]
[react/view {:style styles/details-header}
[react/view {:style styles/details-header-icon}
[list/item-icon (transaction-type->icon type)]]
[react/view {:style styles/details-header-infos}
[react/text {:style styles/details-header-value}
[react/text {:accessibility-label :amount-text}
(pretty-print-asset symbol value token)]
" "
[react/text {:accessibility-label :currency-text}
(clojure.string/upper-case (name symbol))]]
[react/text {:style styles/details-header-date} date]]])
(defn details-header [network {:keys [value date type symbol token]}]
(let [asset (tokens/asset-for (ethereum/network->chain-keyword network) symbol)]
[react/view {:style styles/details-header}
[react/view {:style styles/details-header-icon}
[list/item-icon (transaction-type->icon type)]]
[react/view {:style styles/details-header-infos}
[react/text {:style styles/details-header-value}
[react/text {:accessibility-label :amount-text}
(pretty-print-asset symbol value token)]
" "
[react/text {:accessibility-label :currency-text}
(wallet.utils/display-symbol asset)]]
[react/text {:style styles/details-header-date} date]]]))
(defn progress-bar [progress failed?]
[react/view {:style styles/progress-bar}
@ -242,7 +244,8 @@
(defview transaction-details []
(letsubs [{:keys [hash url type] :as transaction} [:wallet.transactions/transaction-details]
confirmations [:wallet.transactions.details/confirmations]
confirmations-progress [:wallet.transactions.details/confirmations-progress]]
confirmations-progress [:wallet.transactions.details/confirmations-progress]
network [:get-current-account-network]]
[react/view {:style components.styles/flex}
[status-bar/status-bar]
[toolbar/toolbar {}
@ -250,7 +253,7 @@
[toolbar/content-title (i18n/label :t/transaction-details)]
(when transaction [toolbar/actions (details-action hash url)])]
[react/scroll-view {:style components.styles/main-container}
[details-header transaction]
[details-header network transaction]
[details-confirmations confirmations confirmations-progress type]
[react/view {:style styles/details-separator}]
[details-list transaction]]]))

View File

@ -6,3 +6,6 @@
(or (money/bignumber 0))
(money/token->unit decimals)
money/to-fixed))
(defn display-symbol [{:keys [symbol-display symbol]}]
(clojure.core/name (or symbol-display symbol)))

View File

@ -2,20 +2,36 @@
(:require [clojure.string :as string]
[clojure.java.io :as io]))
(defn icon-path
(defn token-icon-path
[network symbol]
(let [s (str "./resources/images/tokens/" (name network) "/" (name symbol) ".png")]
(if (.exists (io/file s))
`(js/require ~s)
`(js/require "./resources/images/tokens/default.png"))))
`(js/require "./resources/images/tokens/default-token.png"))))
(defn- token->icon [network {:keys [icon symbol]}]
;; Tokens can define their own icons.
;; If not try to make one using a local image as resource, if it does not exist fallback to default.
(or icon (icon-path network symbol)))
(or icon (token-icon-path network symbol)))
(defmacro resolve-icons
"In react-native arguments to require must be static strings.
Resolve all icons at compilation time so no variable is used."
[network tokens]
(mapv #(assoc-in % [:icon :source] (token->icon network %)) tokens))
(defn network->icon [network]
(let [s (str "./resources/images/tokens/" (name network) "/0-native.png")]
(if (.exists (io/file s))
`(js/require ~s)
`(js/require "./resources/images/tokens/default-native.png"))))
(defmacro resolve-native-currency-icons
"In react-native arguments to require must be static strings.
Resolve all icons at compilation time so no variable is used."
[all-native-currencies]
(into {}
(map (fn [[network native-currency]]
[network (assoc-in native-currency
[:icon :source]
(network->icon network))]) all-native-currencies)))

View File

@ -1,22 +1,40 @@
(ns status-im.utils.ethereum.tokens
(:require-macros [status-im.utils.ethereum.macros :refer [resolve-icons]])
(:require-macros [status-im.utils.ethereum.macros :refer [resolve-icons] :as ethereum.macros])
(:require [clojure.string :as string]
[status-im.utils.config :as config]))
(defn- asset-border [color]
{:border-color color :border-width 1 :border-radius 32})
(def ethereum {:name "Ether"
:symbol :ETH
:decimals 18
:icon {:source (js/require "./resources/images/assets/ethereum.png")
;; TODO(goranjovic) find a better place to set UI info
;; like colors. Removed the reference to component.styles to
;; avoid circular dependency between namespaces.
:style (asset-border "#628fe333")}})
(def default-native-currency
{:name "Native"
:symbol :ETH
:decimals 18
:icon {:source (js/require "./resources/images/tokens/default-native.png")}})
(defn ethereum? [k]
(= k (:symbol ethereum)))
(def all-native-currencies
(ethereum.macros/resolve-native-currency-icons
{:mainnet {:name "Ether"
:symbol :ETH
:decimals 18
:icon {:style (asset-border "#628fe333")}}
:testnet {:name "Ropsten Ether"
:symbol :ETH
:symbol-display :ETHro
:decimals 18}
:rinkeby {:name "Rinkeby Ether"
:symbol :ETH
:symbol-display :ETHri
:decimals 18}}))
(def native-currency-symbols
(set (map #(-> % val :symbol) all-native-currencies)))
(defn native-currency [chain]
(-> (get all-native-currencies chain default-native-currency)))
(defn ethereum? [symbol]
(native-currency-symbols symbol))
;; symbol are used as global identifier (per network) so they must be unique
@ -466,11 +484,15 @@
:name "KudosToken"
:address "0x93bB0AFbd0627Bbd3a6C72Bc318341D3A22e254a"}])
:custom []})
:custom []})
(defn tokens-for [chain]
(get all chain))
(defn all-assets-for [chain]
(concat [(native-currency chain)]
(tokens-for chain)))
(defn nfts-for [chain]
(filter :nft? (tokens-for chain)))
@ -488,6 +510,8 @@
(string/lower-case (:address %))) %) (tokens-for chain)))
(defn asset-for [chain symbol]
(if (= (:symbol ethereum) symbol)
ethereum
(symbol->token chain symbol)))
(let [native-coin (native-currency chain)]
(if (or (= (:symbol-display native-coin) symbol)
(= (:symbol native-coin) symbol))
native-coin
(symbol->token chain symbol))))

View File

@ -80,8 +80,10 @@
(when bn
(.toNumber bn)))
(defn wei->str [unit n]
(str (to-fixed (wei-> unit n)) " " (string/upper-case (name unit))))
(defn wei->str
([unit n display-unit]
(str (to-fixed (wei-> unit n)) " " display-unit))
([unit n] (wei->str unit n (string/upper-case (name unit)))))
(defn wei->ether [n]
(wei-> :eth n))