fix(swap): display very small max values, fix scientific notation, handle decimal mismatch when changing tokens, display long numbers (#21388)
Signed-off-by: Brian Sztamfater <brian@status.im>
This commit is contained in:
parent
a9e0b3dd6b
commit
5c44cb6399
|
@ -75,3 +75,16 @@
|
||||||
|
|
||||||
(def fiat-amount
|
(def fiat-amount
|
||||||
{:color colors/neutral-50})
|
{:color colors/neutral-50})
|
||||||
|
|
||||||
|
(def gradient-common
|
||||||
|
{:width 64
|
||||||
|
:position :absolute
|
||||||
|
:top 0
|
||||||
|
:bottom 0
|
||||||
|
:z-index 1})
|
||||||
|
|
||||||
|
(def gradient-start
|
||||||
|
(assoc gradient-common :left 0))
|
||||||
|
|
||||||
|
(def gradient-end
|
||||||
|
(assoc gradient-common :right 0))
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
[quo.foundations.colors :as colors]
|
[quo.foundations.colors :as colors]
|
||||||
quo.theme
|
quo.theme
|
||||||
[react-native.core :as rn]
|
[react-native.core :as rn]
|
||||||
|
[react-native.linear-gradient :as linear-gradient]
|
||||||
[schema.core :as schema]))
|
[schema.core :as schema]))
|
||||||
|
|
||||||
(def ?schema
|
(def ?schema
|
||||||
|
@ -18,6 +19,7 @@
|
||||||
[:catn
|
[:catn
|
||||||
[:props
|
[:props
|
||||||
[:map {:closed true}
|
[:map {:closed true}
|
||||||
|
[:get-ref {:optional true} [:maybe fn?]]
|
||||||
[:type {:optional true} [:maybe [:enum :pay :receive]]]
|
[:type {:optional true} [:maybe [:enum :pay :receive]]]
|
||||||
[:status {:optional true} [:maybe [:enum :default :typing :disabled :loading]]]
|
[:status {:optional true} [:maybe [:enum :default :typing :disabled :loading]]]
|
||||||
[:token {:optional true} [:maybe :string]]
|
[:token {:optional true} [:maybe :string]]
|
||||||
|
@ -42,26 +44,65 @@
|
||||||
[:container-style {:optional true} [:maybe :map]]]]]
|
[:container-style {:optional true} [:maybe :map]]]]]
|
||||||
:any])
|
:any])
|
||||||
|
|
||||||
|
(def icon-size 32)
|
||||||
|
(def container-padding (* 2 (:padding (style/row-1 false))))
|
||||||
|
(def max-cursor-position 5)
|
||||||
|
|
||||||
(defn view-internal
|
(defn view-internal
|
||||||
[{:keys [type status token value fiat-value show-approval-label? error? network-tag-props
|
[{:keys [type status token value fiat-value show-approval-label? error? network-tag-props
|
||||||
approval-label-props default-value auto-focus? input-disabled? enable-swap?
|
approval-label-props default-value auto-focus? input-disabled? enable-swap?
|
||||||
currency-symbol on-change-text show-keyboard?
|
currency-symbol on-change-text show-keyboard? get-ref
|
||||||
container-style on-swap-press on-token-press on-max-press on-input-focus]}]
|
container-style on-swap-press on-token-press on-max-press on-input-focus]}]
|
||||||
(let [theme (quo.theme/use-theme)
|
(let [theme (quo.theme/use-theme)
|
||||||
pay? (= type :pay)
|
pay? (= type :pay)
|
||||||
disabled? (= status :disabled)
|
disabled? (= status :disabled)
|
||||||
loading? (= status :loading)
|
loading? (= status :loading)
|
||||||
typing? (= status :typing)
|
typing? (= status :typing)
|
||||||
controlled-input? (some? value)
|
controlled-input? (some? value)
|
||||||
input-ref (rn/use-ref-atom nil)
|
[container-width
|
||||||
set-input-ref (rn/use-callback (fn [ref] (reset! input-ref ref)) [])
|
set-container-width] (rn/use-state)
|
||||||
focus-input (rn/use-callback (fn []
|
[overflow?
|
||||||
(some-> @input-ref
|
set-overflow?] (rn/use-state false)
|
||||||
(oops/ocall "focus")))
|
[cursor-close-to-start?
|
||||||
[input-ref])]
|
set-cursor-close-to-start?] (rn/use-state false)
|
||||||
|
[label-width
|
||||||
|
set-label-width] (rn/use-state 0)
|
||||||
|
input-ref (rn/use-ref-atom nil)
|
||||||
|
set-input-ref (rn/use-callback (fn [ref]
|
||||||
|
(reset! input-ref ref)
|
||||||
|
(when get-ref (get-ref ref)))
|
||||||
|
[])
|
||||||
|
focus-input (rn/use-callback (fn []
|
||||||
|
(some-> @input-ref
|
||||||
|
(oops/ocall "focus")))
|
||||||
|
[input-ref])
|
||||||
|
on-layout-container (rn/use-callback
|
||||||
|
(fn [e]
|
||||||
|
(let [width (oops/oget e "nativeEvent.layout.width")]
|
||||||
|
(set-container-width width))))
|
||||||
|
on-layout-text-input (rn/use-callback
|
||||||
|
(fn [e]
|
||||||
|
(let [width (oops/oget e "nativeEvent.layout.width")
|
||||||
|
max-width (- container-width
|
||||||
|
icon-size
|
||||||
|
container-padding
|
||||||
|
(* label-width 2))]
|
||||||
|
(set-overflow? (> width max-width))))
|
||||||
|
[container-width label-width])
|
||||||
|
on-layout-label (rn/use-callback
|
||||||
|
(fn [e]
|
||||||
|
(let [width (oops/oget e "nativeEvent.layout.width")]
|
||||||
|
(set-label-width width))))
|
||||||
|
on-selection-change (rn/use-callback
|
||||||
|
(fn [e]
|
||||||
|
(let [selection-start (oops/oget e
|
||||||
|
"nativeEvent.selection.start")]
|
||||||
|
(set-cursor-close-to-start?
|
||||||
|
(< selection-start max-cursor-position)))))]
|
||||||
[rn/view
|
[rn/view
|
||||||
{:style container-style
|
{:style container-style
|
||||||
:accessibility-label :swap-input}
|
:accessibility-label :swap-input
|
||||||
|
:on-layout on-layout-container}
|
||||||
[rn/view {:style (style/content typing? theme)}
|
[rn/view {:style (style/content typing? theme)}
|
||||||
[rn/view
|
[rn/view
|
||||||
{:style (style/row-1 loading?)}
|
{:style (style/row-1 loading?)}
|
||||||
|
@ -75,25 +116,43 @@
|
||||||
[rn/pressable
|
[rn/pressable
|
||||||
{:style style/input-container
|
{:style style/input-container
|
||||||
:on-press focus-input}
|
:on-press focus-input}
|
||||||
[rn/text-input
|
[rn/view {:style {:flex-shrink 1}}
|
||||||
(cond-> {:ref set-input-ref
|
(when (and overflow? typing? (not cursor-close-to-start?))
|
||||||
:style (style/input disabled? error? theme)
|
[linear-gradient/linear-gradient
|
||||||
:placeholder-text-color (colors/theme-colors colors/neutral-40
|
{:start {:x 0 :y 0}
|
||||||
colors/neutral-50
|
:end {:x 1 :y 0}
|
||||||
theme)
|
:colors [(colors/theme-colors colors/white colors/neutral-100 theme)
|
||||||
:keyboard-type :numeric
|
(colors/theme-colors colors/white-opa-10 colors/neutral-100-opa-10 theme)]
|
||||||
:editable (not input-disabled?)
|
:style style/gradient-start}])
|
||||||
:auto-focus auto-focus?
|
(when (and overflow? disabled?)
|
||||||
:on-focus on-input-focus
|
[linear-gradient/linear-gradient
|
||||||
:on-change-text on-change-text
|
{:start {:x 0 :y 0}
|
||||||
:show-soft-input-on-focus show-keyboard?
|
:end {:x 1 :y 0}
|
||||||
:default-value default-value
|
:colors [(colors/theme-colors colors/white-opa-10 colors/neutral-100-opa-10 theme)
|
||||||
:placeholder "0"}
|
(colors/theme-colors colors/white colors/neutral-100 theme)]
|
||||||
controlled-input? (assoc :value value))]
|
:style style/gradient-end}])
|
||||||
|
[rn/text-input
|
||||||
|
(cond-> {:ref set-input-ref
|
||||||
|
:style (style/input disabled? error? theme)
|
||||||
|
:placeholder-text-color (colors/theme-colors colors/neutral-40
|
||||||
|
colors/neutral-50
|
||||||
|
theme)
|
||||||
|
:keyboard-type :numeric
|
||||||
|
:editable (not input-disabled?)
|
||||||
|
:auto-focus auto-focus?
|
||||||
|
:on-focus on-input-focus
|
||||||
|
:on-change-text on-change-text
|
||||||
|
:on-layout on-layout-text-input
|
||||||
|
:on-selection-change on-selection-change
|
||||||
|
:show-soft-input-on-focus show-keyboard?
|
||||||
|
:default-value default-value
|
||||||
|
:placeholder "0"}
|
||||||
|
controlled-input? (assoc :value value))]]
|
||||||
[text/text
|
[text/text
|
||||||
{:size :paragraph-2
|
{:size :paragraph-2
|
||||||
:weight :semi-bold
|
:weight :semi-bold
|
||||||
:style (style/token-symbol theme)}
|
:style (style/token-symbol theme)
|
||||||
|
:on-layout on-layout-label}
|
||||||
token]]
|
token]]
|
||||||
(when (and pay? enable-swap?)
|
(when (and pay? enable-swap?)
|
||||||
[buttons/button
|
[buttons/button
|
||||||
|
|
|
@ -47,7 +47,7 @@
|
||||||
(rf/dispatch [:wallet/bridge-select-token params]))})
|
(rf/dispatch [:wallet/bridge-select-token params]))})
|
||||||
|
|
||||||
(defn- action-swap
|
(defn- action-swap
|
||||||
[{:keys [token token-symbol testnet-mode?]}]
|
[{:keys [token asset-to-receive token-symbol testnet-mode?]}]
|
||||||
{:icon :i/swap
|
{:icon :i/swap
|
||||||
:accessibility-label :swap
|
:accessibility-label :swap
|
||||||
:label (i18n/label :t/swap)
|
:label (i18n/label :t/swap)
|
||||||
|
@ -56,6 +56,7 @@
|
||||||
(rf/dispatch [:hide-bottom-sheet])
|
(rf/dispatch [:hide-bottom-sheet])
|
||||||
(rf/dispatch [:wallet.swap/start
|
(rf/dispatch [:wallet.swap/start
|
||||||
{:asset-to-pay (or token {:symbol token-symbol})
|
{:asset-to-pay (or token {:symbol token-symbol})
|
||||||
|
:asset-to-receive asset-to-receive
|
||||||
:open-new-screen? true}]))})
|
:open-new-screen? true}]))})
|
||||||
|
|
||||||
(defn- action-manage-tokens
|
(defn- action-manage-tokens
|
||||||
|
@ -75,23 +76,26 @@
|
||||||
|
|
||||||
(defn token-value-drawer
|
(defn token-value-drawer
|
||||||
[token watch-only? entry-point]
|
[token watch-only? entry-point]
|
||||||
(let [token-symbol (:token token)
|
(let [token-symbol (:token token)
|
||||||
token-data (first (rf/sub [:wallet/current-viewing-account-tokens-filtered
|
token-data (first (rf/sub [:wallet/current-viewing-account-tokens-filtered
|
||||||
{:query token-symbol}]))
|
{:query token-symbol}]))
|
||||||
selected-account (rf/sub [:wallet/current-viewing-account-address])
|
selected-account (rf/sub [:wallet/current-viewing-account-address])
|
||||||
token-owners (rf/sub [:wallet/operable-addresses-with-token-symbol token-symbol])
|
token-owners (rf/sub [:wallet/operable-addresses-with-token-symbol token-symbol])
|
||||||
testnet-mode? (rf/sub [:profile/test-networks-enabled?])
|
testnet-mode? (rf/sub [:profile/test-networks-enabled?])
|
||||||
params (cond-> {:start-flow? true
|
receive-token-symbol (if (= token-symbol "SNT") "ETH" "SNT")
|
||||||
:owners token-owners
|
asset-to-receive (rf/sub [:wallet/token-by-symbol receive-token-symbol])
|
||||||
:testnet-mode? testnet-mode?}
|
params (cond-> {:start-flow? true
|
||||||
selected-account
|
:owners token-owners
|
||||||
(assoc :token token-data
|
:testnet-mode? testnet-mode?
|
||||||
:stack-id :screen/wallet.accounts
|
:asset-to-receive asset-to-receive}
|
||||||
:has-balance? (-> (get-in token [:values :fiat-unformatted-value])
|
selected-account
|
||||||
(money/greater-than (money/bignumber "0"))))
|
(assoc :token token-data
|
||||||
(not selected-account)
|
:stack-id :screen/wallet.accounts
|
||||||
(assoc :token-symbol token-symbol
|
:has-balance? (-> (get-in token [:values :fiat-unformatted-value])
|
||||||
:stack-id :wallet-stack))]
|
(money/greater-than (money/bignumber "0"))))
|
||||||
|
(not selected-account)
|
||||||
|
(assoc :token-symbol token-symbol
|
||||||
|
:stack-id :wallet-stack))]
|
||||||
[quo/action-drawer
|
[quo/action-drawer
|
||||||
[(cond->> [(when (ff/enabled? ::ff/wallet.assets-modal-manage-tokens)
|
[(cond->> [(when (ff/enabled? ::ff/wallet.assets-modal-manage-tokens)
|
||||||
(action-manage-tokens watch-only?))
|
(action-manage-tokens watch-only?))
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
[utils.number :as number]))
|
[utils.number :as number]))
|
||||||
|
|
||||||
(rf/reg-event-fx :wallet.swap/start
|
(rf/reg-event-fx :wallet.swap/start
|
||||||
(fn [{:keys [db]} [{:keys [network open-new-screen?] :as data}]]
|
(fn [{:keys [db]} [{:keys [network asset-to-receive open-new-screen?] :as data}]]
|
||||||
(let [{:keys [wallet]} db
|
(let [{:keys [wallet]} db
|
||||||
test-networks-enabled? (get-in db [:profile/profile :test-networks-enabled?])
|
test-networks-enabled? (get-in db [:profile/profile :test-networks-enabled?])
|
||||||
account (swap-utils/wallet-account wallet)
|
account (swap-utils/wallet-account wallet)
|
||||||
|
@ -25,12 +25,6 @@
|
||||||
:account account
|
:account account
|
||||||
:test-networks-enabled? test-networks-enabled?
|
:test-networks-enabled? test-networks-enabled?
|
||||||
:token-symbol (get-in data [:asset-to-pay :symbol])}))
|
:token-symbol (get-in data [:asset-to-pay :symbol])}))
|
||||||
asset-to-receive (or (:asset-to-receive data)
|
|
||||||
(swap-utils/select-default-asset-to-receive
|
|
||||||
{:wallet wallet
|
|
||||||
:account account
|
|
||||||
:test-networks-enabled? test-networks-enabled?
|
|
||||||
:asset-to-pay asset-to-pay}))
|
|
||||||
network' (or network
|
network' (or network
|
||||||
(swap-utils/select-network asset-to-pay))]
|
(swap-utils/select-network asset-to-pay))]
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
|
@ -137,8 +131,6 @@
|
||||||
:amount amount
|
:amount amount
|
||||||
:amount-hex amount-in-hex
|
:amount-hex amount-in-hex
|
||||||
:loading-swap-proposal? true)
|
:loading-swap-proposal? true)
|
||||||
:always
|
|
||||||
(dissoc :error-response)
|
|
||||||
clean-approval-transaction?
|
clean-approval-transaction?
|
||||||
(dissoc :approval-transaction-id :approved-amount :swap-proposal)))
|
(dissoc :approval-transaction-id :approved-amount :swap-proposal)))
|
||||||
:json-rpc/call [{:method "wallet_getSuggestedRoutesAsync"
|
:json-rpc/call [{:method "wallet_getSuggestedRoutesAsync"
|
||||||
|
|
|
@ -20,10 +20,15 @@
|
||||||
|
|
||||||
(defn- assets-view
|
(defn- assets-view
|
||||||
[search-text on-change-text]
|
[search-text on-change-text]
|
||||||
(let [on-token-press (fn [token]
|
(let [snt-token (rf/sub [:wallet/token-by-symbol "SNT"])
|
||||||
(rf/dispatch [:wallet.swap/start
|
eth-token (rf/sub [:wallet/token-by-symbol "ETH"])
|
||||||
{:asset-to-pay token
|
on-token-press (fn [token]
|
||||||
:open-new-screen? false}]))]
|
(let [pay-token-symbol (:symbol token)
|
||||||
|
asset-to-receive (if (= pay-token-symbol "SNT") eth-token snt-token)]
|
||||||
|
(rf/dispatch [:wallet.swap/start
|
||||||
|
{:asset-to-pay token
|
||||||
|
:asset-to-receive asset-to-receive
|
||||||
|
:open-new-screen? false}])))]
|
||||||
[:<>
|
[:<>
|
||||||
[search-input search-text on-change-text]
|
[search-input search-text on-change-text]
|
||||||
[asset-list/view
|
[asset-list/view
|
||||||
|
|
|
@ -1,27 +1,29 @@
|
||||||
(ns status-im.contexts.wallet.swap.setup-swap.view
|
(ns status-im.contexts.wallet.swap.setup-swap.view
|
||||||
(:require [clojure.string :as string]
|
(:require
|
||||||
[quo.core :as quo]
|
[clojure.string :as string]
|
||||||
[quo.foundations.colors :as colors]
|
[oops.core :as oops]
|
||||||
[quo.theme :as quo.theme]
|
[quo.core :as quo]
|
||||||
[react-native.core :as rn]
|
[quo.foundations.colors :as colors]
|
||||||
[react-native.platform :as platform]
|
[quo.theme :as quo.theme]
|
||||||
[react-native.safe-area :as safe-area]
|
[react-native.core :as rn]
|
||||||
[status-im.common.controlled-input.utils :as controlled-input]
|
[react-native.platform :as platform]
|
||||||
[status-im.common.events-helper :as events-helper]
|
[react-native.safe-area :as safe-area]
|
||||||
[status-im.constants :as constants]
|
[status-im.common.controlled-input.utils :as controlled-input]
|
||||||
[status-im.contexts.wallet.common.account-switcher.view :as account-switcher]
|
[status-im.common.events-helper :as events-helper]
|
||||||
[status-im.contexts.wallet.common.utils :as utils]
|
[status-im.constants :as constants]
|
||||||
[status-im.contexts.wallet.sheets.buy-token.view :as buy-token]
|
[status-im.contexts.wallet.common.account-switcher.view :as account-switcher]
|
||||||
[status-im.contexts.wallet.sheets.select-asset.view :as select-asset]
|
[status-im.contexts.wallet.common.utils :as utils]
|
||||||
[status-im.contexts.wallet.sheets.slippage-settings.view :as slippage-settings]
|
[status-im.contexts.wallet.sheets.buy-token.view :as buy-token]
|
||||||
[status-im.contexts.wallet.swap.setup-swap.style :as style]
|
[status-im.contexts.wallet.sheets.select-asset.view :as select-asset]
|
||||||
[status-im.contexts.wallet.swap.utils :as swap-utils]
|
[status-im.contexts.wallet.sheets.slippage-settings.view :as slippage-settings]
|
||||||
[utils.debounce :as debounce]
|
[status-im.contexts.wallet.swap.setup-swap.style :as style]
|
||||||
[utils.i18n :as i18n]
|
[status-im.contexts.wallet.swap.utils :as swap-utils]
|
||||||
[utils.money :as money]
|
[utils.debounce :as debounce]
|
||||||
[utils.number :as number]
|
[utils.i18n :as i18n]
|
||||||
[utils.re-frame :as rf]
|
[utils.money :as money]
|
||||||
[utils.string :as utils.string]))
|
[utils.number :as number]
|
||||||
|
[utils.re-frame :as rf]
|
||||||
|
[utils.string :as utils.string]))
|
||||||
|
|
||||||
(def ^:private default-text-for-unfocused-input "0.00")
|
(def ^:private default-text-for-unfocused-input "0.00")
|
||||||
|
|
||||||
|
@ -97,13 +99,18 @@
|
||||||
approved-amount (rf/sub [:wallet/swap-approved-amount])
|
approved-amount (rf/sub [:wallet/swap-approved-amount])
|
||||||
error-response (rf/sub [:wallet/swap-error-response])
|
error-response (rf/sub [:wallet/swap-error-response])
|
||||||
asset-to-pay (rf/sub [:wallet/token-by-symbol pay-token-symbol])
|
asset-to-pay (rf/sub [:wallet/token-by-symbol pay-token-symbol])
|
||||||
|
overlay-shown? (boolean (:sheets (rf/sub [:bottom-sheet])))
|
||||||
|
input-ref (rn/use-ref-atom nil)
|
||||||
|
set-input-ref (rn/use-callback (fn [ref] (reset! input-ref ref)))
|
||||||
pay-input-num-value (controlled-input/value-numeric input-state)
|
pay-input-num-value (controlled-input/value-numeric input-state)
|
||||||
pay-input-amount (controlled-input/input-value input-state)
|
pay-input-amount (controlled-input/input-value input-state)
|
||||||
pay-token-decimals (:decimals asset-to-pay)
|
pay-token-decimals (:decimals asset-to-pay)
|
||||||
pay-token-balance-selected-chain (get-in asset-to-pay
|
pay-token-balance-selected-chain (number/convert-to-whole-number
|
||||||
[:balances-per-chain
|
(get-in asset-to-pay
|
||||||
(:chain-id network) :balance]
|
[:balances-per-chain
|
||||||
0)
|
(:chain-id network) :raw-balance]
|
||||||
|
0)
|
||||||
|
pay-token-decimals)
|
||||||
pay-token-fiat-value (str
|
pay-token-fiat-value (str
|
||||||
(utils/calculate-token-fiat-value
|
(utils/calculate-token-fiat-value
|
||||||
{:currency currency
|
{:currency currency
|
||||||
|
@ -111,10 +118,15 @@
|
||||||
:token asset-to-pay}))
|
:token asset-to-pay}))
|
||||||
available-crypto-limit (money/bignumber
|
available-crypto-limit (money/bignumber
|
||||||
pay-token-balance-selected-chain)
|
pay-token-balance-selected-chain)
|
||||||
|
display-decimals (min pay-token-decimals
|
||||||
|
constants/min-token-decimals-to-display)
|
||||||
available-crypto-limit-display (number/remove-trailing-zeroes
|
available-crypto-limit-display (number/remove-trailing-zeroes
|
||||||
(.toFixed available-crypto-limit
|
(.toFixed available-crypto-limit display-decimals))
|
||||||
(min pay-token-decimals
|
available-crypto-limit-display (if (and (= available-crypto-limit-display "0")
|
||||||
constants/min-token-decimals-to-display)))
|
(money/greater-than available-crypto-limit
|
||||||
|
(money/bignumber 0)))
|
||||||
|
(number/small-number-threshold display-decimals)
|
||||||
|
available-crypto-limit-display)
|
||||||
approval-amount-required-num (when approval-amount-required
|
approval-amount-required-num (when approval-amount-required
|
||||||
(str (number/hex->whole approval-amount-required
|
(str (number/hex->whole approval-amount-required
|
||||||
pay-token-decimals)))
|
pay-token-decimals)))
|
||||||
|
@ -122,8 +134,7 @@
|
||||||
(money/greater-than
|
(money/greater-than
|
||||||
(money/bignumber pay-input-amount)
|
(money/bignumber pay-input-amount)
|
||||||
available-crypto-limit))
|
available-crypto-limit))
|
||||||
(money/equal-to (money/bignumber
|
(money/equal-to available-crypto-limit
|
||||||
available-crypto-limit-display)
|
|
||||||
(money/bignumber 0)))
|
(money/bignumber 0)))
|
||||||
valid-pay-input? (and
|
valid-pay-input? (and
|
||||||
(not (string/blank?
|
(not (string/blank?
|
||||||
|
@ -141,8 +152,15 @@
|
||||||
(fn []
|
(fn []
|
||||||
(request-fetch-swap-proposal))
|
(request-fetch-swap-proposal))
|
||||||
[pay-input-amount])
|
[pay-input-amount])
|
||||||
|
(rn/use-effect
|
||||||
|
(fn []
|
||||||
|
(when-not overlay-shown?
|
||||||
|
(some-> @input-ref
|
||||||
|
(oops/ocall "focus"))))
|
||||||
|
[overlay-shown?])
|
||||||
[quo/swap-input
|
[quo/swap-input
|
||||||
{:type :pay
|
{:get-ref set-input-ref
|
||||||
|
:type :pay
|
||||||
:error? pay-input-error?
|
:error? pay-input-error?
|
||||||
:token pay-token-symbol
|
:token pay-token-symbol
|
||||||
:customization-color :blue
|
:customization-color :blue
|
||||||
|
@ -156,7 +174,7 @@
|
||||||
:else :disabled)
|
:else :disabled)
|
||||||
:currency-symbol currency-symbol
|
:currency-symbol currency-symbol
|
||||||
:on-token-press on-token-press
|
:on-token-press on-token-press
|
||||||
:on-max-press #(on-max-press (str available-crypto-limit))
|
:on-max-press #(on-max-press (str pay-token-balance-selected-chain))
|
||||||
:on-input-focus on-input-focus
|
:on-input-focus on-input-focus
|
||||||
:value pay-input-amount
|
:value pay-input-amount
|
||||||
:fiat-value pay-token-fiat-value
|
:fiat-value pay-token-fiat-value
|
||||||
|
@ -315,10 +333,12 @@
|
||||||
network (rf/sub [:wallet/swap-network])
|
network (rf/sub [:wallet/swap-network])
|
||||||
pay-input-amount (controlled-input/input-value pay-input-state)
|
pay-input-amount (controlled-input/input-value pay-input-state)
|
||||||
pay-token-decimals (:decimals asset-to-pay)
|
pay-token-decimals (:decimals asset-to-pay)
|
||||||
pay-token-balance-selected-chain (get-in asset-to-pay
|
pay-token-balance-selected-chain (number/convert-to-whole-number
|
||||||
[:balances-per-chain
|
(get-in asset-to-pay
|
||||||
(:chain-id network) :balance]
|
[:balances-per-chain
|
||||||
0)
|
(:chain-id network) :raw-balance]
|
||||||
|
0)
|
||||||
|
pay-token-decimals)
|
||||||
pay-input-error? (and (not (string/blank? pay-input-amount))
|
pay-input-error? (and (not (string/blank? pay-input-amount))
|
||||||
(money/greater-than
|
(money/greater-than
|
||||||
(money/bignumber pay-input-amount)
|
(money/bignumber pay-input-amount)
|
||||||
|
@ -420,13 +440,17 @@
|
||||||
(when (and swap-amount refetch-interval)
|
(when (and swap-amount refetch-interval)
|
||||||
(js/clearTimeout @refetch-interval)
|
(js/clearTimeout @refetch-interval)
|
||||||
(reset! refetch-interval nil))
|
(reset! refetch-interval nil))
|
||||||
(if (and swap-amount (not= swap-amount pay-input-amount))
|
(cond (and swap-amount (not= swap-amount pay-input-amount))
|
||||||
(set-pay-input-state
|
(set-pay-input-state
|
||||||
(fn [input-state]
|
(fn [input-state]
|
||||||
(controlled-input/set-input-value
|
(controlled-input/set-input-value
|
||||||
input-state
|
input-state
|
||||||
swap-amount)))
|
swap-amount)))
|
||||||
(refetch-swap-proposal)))))
|
(and pay-input-amount
|
||||||
|
(not (number/valid-decimal-count? pay-input-amount (:decimals asset-to-pay))))
|
||||||
|
(set-pay-input-state controlled-input/delete-all)
|
||||||
|
:else
|
||||||
|
(refetch-swap-proposal)))))
|
||||||
[asset-to-pay])
|
[asset-to-pay])
|
||||||
(rn/use-effect
|
(rn/use-effect
|
||||||
refetch-swap-proposal
|
refetch-swap-proposal
|
||||||
|
@ -461,7 +485,7 @@
|
||||||
:on-token-press #(rf/dispatch [:show-bottom-sheet {:content receive-token-bottom-sheet}])
|
:on-token-press #(rf/dispatch [:show-bottom-sheet {:content receive-token-bottom-sheet}])
|
||||||
:on-input-focus #(set-pay-input-focused? false)}]]
|
:on-input-focus #(set-pay-input-focused? false)}]]
|
||||||
[rn/view {:style style/footer-container}
|
[rn/view {:style style/footer-container}
|
||||||
[alert-banner {:pay-input-error? pay-input-error?}]
|
(when-not loading-swap-proposal? [alert-banner {:pay-input-error? pay-input-error?}])
|
||||||
(when (or loading-swap-proposal? swap-proposal)
|
(when (or loading-swap-proposal? swap-proposal)
|
||||||
[transaction-details])
|
[transaction-details])
|
||||||
[action-button {:on-press on-review-swap-press}]]
|
[action-button {:on-press on-review-swap-press}]]
|
||||||
|
|
|
@ -492,7 +492,7 @@
|
||||||
|
|
||||||
(rf/reg-sub
|
(rf/reg-sub
|
||||||
:wallet/token-by-symbol
|
:wallet/token-by-symbol
|
||||||
:<- [:wallet/current-viewing-account]
|
:<- [:wallet/current-viewing-account-or-default]
|
||||||
:<- [:wallet/network-details]
|
:<- [:wallet/network-details]
|
||||||
(fn [[{:keys [tokens]} networks] [_ token-symbol chain-ids]]
|
(fn [[{:keys [tokens]} networks] [_ token-symbol chain-ids]]
|
||||||
(->> (utils/tokens-with-balance tokens networks chain-ids)
|
(->> (utils/tokens-with-balance tokens networks chain-ids)
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
(:require [clojure.string :as string]
|
(:require [clojure.string :as string]
|
||||||
[native-module.core :as native-module]
|
[native-module.core :as native-module]
|
||||||
[utils.hex :as utils.hex]
|
[utils.hex :as utils.hex]
|
||||||
[utils.money :as utils.money]))
|
[utils.money :as utils.money]
|
||||||
|
[utils.money :as money]))
|
||||||
|
|
||||||
(defn naive-round
|
(defn naive-round
|
||||||
"Quickly and naively round number `n` up to `decimal-places`.
|
"Quickly and naively round number `n` up to `decimal-places`.
|
||||||
|
@ -18,17 +19,6 @@
|
||||||
(/ (Math/round (* n scale))
|
(/ (Math/round (* n scale))
|
||||||
scale)))
|
scale)))
|
||||||
|
|
||||||
(defn convert-to-whole-number
|
|
||||||
"Converts a fractional `amount` to its corresponding whole number representation
|
|
||||||
by dividing it by 10 raised to the power of `decimals`. This is often used in financial
|
|
||||||
calculations where amounts are stored in their smallest units (e.g., cents) and need
|
|
||||||
to be converted to their whole number equivalents (e.g., dollars).
|
|
||||||
|
|
||||||
Example usage:
|
|
||||||
(convert-to-whole-number 12345 2) ; => 123.45"
|
|
||||||
[amount decimals]
|
|
||||||
(/ amount (Math/pow 10 decimals)))
|
|
||||||
|
|
||||||
(defn parse-int
|
(defn parse-int
|
||||||
"Parses `n` as an integer. Defaults to zero or `default` instead of NaN."
|
"Parses `n` as an integer. Defaults to zero or `default` instead of NaN."
|
||||||
([n]
|
([n]
|
||||||
|
@ -65,15 +55,44 @@
|
||||||
"")
|
"")
|
||||||
""))))
|
""))))
|
||||||
|
|
||||||
|
(defn convert-to-whole-number
|
||||||
|
"Converts a fractional `amount` to its corresponding whole number representation
|
||||||
|
by dividing it by 10 raised to the power of `decimals`. This is often used in financial
|
||||||
|
calculations where amounts are stored in their smallest units (e.g., cents) and need
|
||||||
|
to be converted to their whole number equivalents (e.g., dollars).
|
||||||
|
|
||||||
|
Example usage:
|
||||||
|
(convert-to-whole-number 12345 2) ; => 123.45"
|
||||||
|
[amount decimals]
|
||||||
|
(-> amount
|
||||||
|
(/ (Math/pow 10 decimals))
|
||||||
|
(.toFixed decimals)
|
||||||
|
remove-trailing-zeroes))
|
||||||
|
|
||||||
(defn hex->whole
|
(defn hex->whole
|
||||||
[num decimals]
|
[num decimals]
|
||||||
(-> num
|
(-> num
|
||||||
utils.hex/normalize-hex
|
utils.hex/normalize-hex
|
||||||
native-module/hex-to-number
|
native-module/hex-to-number
|
||||||
(convert-to-whole-number decimals)))
|
(convert-to-whole-number decimals)
|
||||||
|
money/bignumber))
|
||||||
|
|
||||||
(defn to-fixed
|
(defn to-fixed
|
||||||
[num decimals]
|
[num decimals]
|
||||||
(-> num
|
(-> num
|
||||||
(utils.money/to-fixed decimals)
|
(utils.money/to-fixed decimals)
|
||||||
remove-trailing-zeroes))
|
remove-trailing-zeroes))
|
||||||
|
|
||||||
|
(defn small-number-threshold
|
||||||
|
"Receives a decimal count and returns a string like '<0.001' if the decimal count is 3,
|
||||||
|
'<0.000001' if the decimal count is 6, etc."
|
||||||
|
[decimal-count]
|
||||||
|
(if (> decimal-count 0)
|
||||||
|
(str "<0." (apply str (repeat (dec decimal-count) "0")) "1")
|
||||||
|
"0"))
|
||||||
|
|
||||||
|
(defn valid-decimal-count?
|
||||||
|
"Returns false if the number has more decimals than the decimal count, otherwise true."
|
||||||
|
[num decimal-count]
|
||||||
|
(let [decimal-part (second (string/split (str num) #"\."))]
|
||||||
|
(or (nil? decimal-part) (<= (count decimal-part) decimal-count))))
|
||||||
|
|
|
@ -5,23 +5,23 @@
|
||||||
|
|
||||||
(deftest convert-to-whole-number-test
|
(deftest convert-to-whole-number-test
|
||||||
(testing "correctly converts fractional amounts to whole numbers"
|
(testing "correctly converts fractional amounts to whole numbers"
|
||||||
(is (= 123.45 (utils.number/convert-to-whole-number 12345 2)))
|
(is (= "123.45" (utils.number/convert-to-whole-number 12345 2)))
|
||||||
(is (= 1.2345 (utils.number/convert-to-whole-number 12345 4)))
|
(is (= "1.2345" (utils.number/convert-to-whole-number 12345 4)))
|
||||||
(is (= 12345.0 (utils.number/convert-to-whole-number 1234500 2)))
|
(is (= "12345" (utils.number/convert-to-whole-number 1234500 2)))
|
||||||
(is (= 0.123 (utils.number/convert-to-whole-number 123 3)))
|
(is (= "0.123" (utils.number/convert-to-whole-number 123 3)))
|
||||||
(is (= 1000.0 (utils.number/convert-to-whole-number 1000000 3))))
|
(is (= "1000" (utils.number/convert-to-whole-number 1000000 3))))
|
||||||
|
|
||||||
(testing "handles zero decimals"
|
(testing "handles zero decimals"
|
||||||
(is (= 12345 (utils.number/convert-to-whole-number 12345 0))))
|
(is (= "12345" (utils.number/convert-to-whole-number 12345 0))))
|
||||||
|
|
||||||
(testing "handles negative amounts"
|
(testing "handles negative amounts"
|
||||||
(is (= -123.45 (utils.number/convert-to-whole-number -12345 2)))
|
(is (= "-123.45" (utils.number/convert-to-whole-number -12345 2)))
|
||||||
(is (= -1.2345 (utils.number/convert-to-whole-number -12345 4)))
|
(is (= "-1.2345" (utils.number/convert-to-whole-number -12345 4)))
|
||||||
(is (= -0.123 (utils.number/convert-to-whole-number -123 3))))
|
(is (= "-0.123" (utils.number/convert-to-whole-number -123 3))))
|
||||||
|
|
||||||
(testing "handles zero amount"
|
(testing "handles zero amount"
|
||||||
(is (= 0 (utils.number/convert-to-whole-number 0 2)))
|
(is (= "0" (utils.number/convert-to-whole-number 0 2)))
|
||||||
(is (= 0 (utils.number/convert-to-whole-number 0 0)))))
|
(is (= "0" (utils.number/convert-to-whole-number 0 0)))))
|
||||||
|
|
||||||
(deftest parse-int-test
|
(deftest parse-int-test
|
||||||
(testing "defaults to zero"
|
(testing "defaults to zero"
|
||||||
|
@ -50,3 +50,36 @@
|
||||||
(is (= 6 (utils.number/parse-float "6")))
|
(is (= 6 (utils.number/parse-float "6")))
|
||||||
(is (= 6.99 (utils.number/parse-float "6.99" 0)))
|
(is (= 6.99 (utils.number/parse-float "6.99" 0)))
|
||||||
(is (= -6.9 (utils.number/parse-float "-6.9" 0)))))
|
(is (= -6.9 (utils.number/parse-float "-6.9" 0)))))
|
||||||
|
|
||||||
|
(deftest small-number-threshold-test
|
||||||
|
(testing "correctly generates threshold strings based on decimal count"
|
||||||
|
(is (= "<0.1" (utils.number/small-number-threshold 1)))
|
||||||
|
(is (= "<0.01" (utils.number/small-number-threshold 2)))
|
||||||
|
(is (= "<0.001" (utils.number/small-number-threshold 3)))
|
||||||
|
(is (= "<0.000001" (utils.number/small-number-threshold 6)))
|
||||||
|
(is (= "<0.0000000001" (utils.number/small-number-threshold 10)))
|
||||||
|
(is (= "<0.000000000000000001" (utils.number/small-number-threshold 18)))
|
||||||
|
(is (= "<0.000000000000000000001" (utils.number/small-number-threshold 21))))
|
||||||
|
|
||||||
|
(testing "handles edge cases for decimal count"
|
||||||
|
(is (= "0" (utils.number/small-number-threshold 0)))
|
||||||
|
(is (= "0" (utils.number/small-number-threshold -1)))))
|
||||||
|
|
||||||
|
(deftest valid-decimal-count?-test
|
||||||
|
(testing "valid decimal count check for numbers with varying decimals"
|
||||||
|
(is (true? (utils.number/valid-decimal-count? 123 2)))
|
||||||
|
(is (true? (utils.number/valid-decimal-count? 123 0)))
|
||||||
|
|
||||||
|
(is (true? (utils.number/valid-decimal-count? 123.45 2)))
|
||||||
|
(is (true? (utils.number/valid-decimal-count? 123.4 2)))
|
||||||
|
(is (true? (utils.number/valid-decimal-count? 123.456 3)))
|
||||||
|
|
||||||
|
(is (false? (utils.number/valid-decimal-count? 123.456 2)))
|
||||||
|
(is (false? (utils.number/valid-decimal-count? 123.456789 4)))
|
||||||
|
|
||||||
|
(is (true? (utils.number/valid-decimal-count? 123.0 1)))
|
||||||
|
(is (true? (utils.number/valid-decimal-count? -123.45 2)))
|
||||||
|
(is (false? (utils.number/valid-decimal-count? -123.4567 3)))
|
||||||
|
|
||||||
|
(is (true? (utils.number/valid-decimal-count? 1234567890.12 2)))
|
||||||
|
(is (false? (utils.number/valid-decimal-count? 1234567890.12345 3)))))
|
||||||
|
|
Loading…
Reference in New Issue