[BUG #1990] Improved amount validation in wallet/send screen
This commit is contained in:
parent
10752aeb5e
commit
23eeadf95a
1
.env
1
.env
|
@ -1,5 +1,4 @@
|
||||||
TESTFAIRY_ENABLED=0
|
TESTFAIRY_ENABLED=0
|
||||||
WALLET_WIP_ENABLED=1
|
|
||||||
NOTIFICATIONS_WIP_ENABLED=1
|
NOTIFICATIONS_WIP_ENABLED=1
|
||||||
DEBUG_LOGS_ENABLED=1
|
DEBUG_LOGS_ENABLED=1
|
||||||
STUB_STATUS_GO=0
|
STUB_STATUS_GO=0
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
TESTFAIRY_ENABLED=1
|
TESTFAIRY_ENABLED=1
|
||||||
WALLET_WIP_ENABLED=1
|
|
||||||
NOTIFICATIONS_WIP_ENABLED=1
|
NOTIFICATIONS_WIP_ENABLED=1
|
||||||
DEBUG_LOGS_ENABLED=1
|
DEBUG_LOGS_ENABLED=1
|
||||||
STUB_STATUS_GO=0
|
STUB_STATUS_GO=0
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
TESTFAIRY_ENABLED=0
|
TESTFAIRY_ENABLED=0
|
||||||
WALLET_WIP_ENABLED=0
|
|
||||||
NOTIFICATIONS_WIP_ENABLED=0
|
NOTIFICATIONS_WIP_ENABLED=0
|
||||||
DEBUG_LOGS_ENABLED=0
|
DEBUG_LOGS_ENABLED=0
|
|
@ -3,46 +3,34 @@
|
||||||
[status-im.components.react :as react]
|
[status-im.components.react :as react]
|
||||||
[status-im.utils.platform :as platform]))
|
[status-im.utils.platform :as platform]))
|
||||||
|
|
||||||
(defn- button [{:keys [on-press style text text-style disabled? fit-to-text?]}]
|
(defn button-text [{:keys [disabled? text-style]} label]
|
||||||
|
[react/text {:style (merge (button.styles/button-text disabled?)
|
||||||
|
text-style)
|
||||||
|
:font (if platform/android? :medium :default)
|
||||||
|
:uppercase? (get-in platform/platform-specific [:uppercase?])}
|
||||||
|
label])
|
||||||
|
|
||||||
|
(defn button [{:keys [on-press style disabled? fit-to-text?] :as props} label]
|
||||||
[react/touchable-highlight (merge {:underlay-color button.styles/border-color-high}
|
[react/touchable-highlight (merge {:underlay-color button.styles/border-color-high}
|
||||||
(when-not fit-to-text?
|
(when-not fit-to-text?
|
||||||
{:style button.styles/button-container})
|
{:style button.styles/button-container})
|
||||||
(when (and on-press
|
(when (and on-press (not disabled?))
|
||||||
(not disabled?))
|
|
||||||
{:on-press on-press}))
|
{:on-press on-press}))
|
||||||
[react/view {:style (merge (button.styles/button disabled?)
|
[react/view {:style (merge (button.styles/button disabled?)
|
||||||
style)}
|
style)}
|
||||||
[react/text {:style (merge (button.styles/button-text disabled?)
|
[button-text props
|
||||||
text-style)
|
label]]])
|
||||||
:font :medium
|
|
||||||
:uppercase? platform/android?}
|
|
||||||
text]]])
|
|
||||||
|
|
||||||
(defn primary-button [{:keys [style text-style] :as m}]
|
(defn primary-button [{:keys [style text-style] :as m} label]
|
||||||
(button (assoc m
|
[button (assoc m
|
||||||
:fit-to-text? true
|
:fit-to-text? true
|
||||||
:style (merge button.styles/primary-button style)
|
:style (merge button.styles/primary-button style)
|
||||||
:text-style (merge button.styles/primary-button-text text-style))))
|
:text-style (merge button.styles/primary-button-text text-style))
|
||||||
|
label])
|
||||||
|
|
||||||
(defn secondary-button [{:keys [style text-style] :as m}]
|
(defn secondary-button [{:keys [style text-style] :as m} label]
|
||||||
(button (assoc m
|
[button (assoc m
|
||||||
:fit-to-text? true
|
:fit-to-text? true
|
||||||
:style (merge button.styles/secondary-button style)
|
:style (merge button.styles/secondary-button style)
|
||||||
:text-style (merge button.styles/secondary-button-text text-style))))
|
:text-style (merge button.styles/secondary-button-text text-style))
|
||||||
|
label])
|
||||||
(defn- position [i v]
|
|
||||||
(cond
|
|
||||||
(zero? i) :first
|
|
||||||
(= i (dec (count v))) :last
|
|
||||||
:else :other))
|
|
||||||
|
|
||||||
(defn buttons
|
|
||||||
([v] (buttons nil v))
|
|
||||||
([{:keys [style button-text-style]} v]
|
|
||||||
[react/view {:style (merge button.styles/buttons-container style)}
|
|
||||||
(doall
|
|
||||||
(map-indexed
|
|
||||||
(fn [i m] ^{:key i} [button (merge m
|
|
||||||
{:style (button.styles/button-bar (position i v))
|
|
||||||
:text-style button-text-style})])
|
|
||||||
v))]))
|
|
||||||
|
|
|
@ -362,6 +362,7 @@
|
||||||
:wallet-total-value "Total value"
|
:wallet-total-value "Total value"
|
||||||
:wallet-settings "Wallet Settings"
|
:wallet-settings "Wallet Settings"
|
||||||
:signing-phrase-description "Sign the transaction by entering your password. Make sure that the words above match your secret signing phrase"
|
:signing-phrase-description "Sign the transaction by entering your password. Make sure that the words above match your secret signing phrase"
|
||||||
|
:wallet-insufficient-funds "Insufficient funds"
|
||||||
:request-transaction "Request Transaction"
|
:request-transaction "Request Transaction"
|
||||||
:send-request "Send request"
|
:send-request "Send request"
|
||||||
:share "Share"
|
:share "Share"
|
||||||
|
@ -385,7 +386,7 @@
|
||||||
:view-transaction-details "View Transaction Details"
|
:view-transaction-details "View Transaction Details"
|
||||||
:transaction-description "If you want to be sure you transaction will not be compromised wait until it gets at least 10 block confirmations"
|
:transaction-description "If you want to be sure you transaction will not be compromised wait until it gets at least 10 block confirmations"
|
||||||
:transaction-sent "Transaction Sent"
|
:transaction-sent "Transaction Sent"
|
||||||
:transaction-moved-text "The transaction has ben successfully moved to “Unsigned”"
|
:transaction-moved-text "The transaction has been successfully moved to “Unsigned”"
|
||||||
:transaction-moved-title "Transaction Moved"
|
:transaction-moved-title "Transaction Moved"
|
||||||
:sign-later-title "Sign Transaction Later?"
|
:sign-later-title "Sign Transaction Later?"
|
||||||
:sign-later-text "You will be able to sign in in the transaction history"
|
:sign-later-text "You will be able to sign in in the transaction history"
|
||||||
|
@ -398,7 +399,8 @@
|
||||||
:wallet-choose-from-contacts "Choose From Contacts"
|
:wallet-choose-from-contacts "Choose From Contacts"
|
||||||
:wallet-address-from-clipboard "Use Address From Clipboard"
|
:wallet-address-from-clipboard "Use Address From Clipboard"
|
||||||
:wallet-browse-photos "Browse Photos"
|
:wallet-browse-photos "Browse Photos"
|
||||||
:validation-amount-invalid-number "Amount is not valid number"
|
:validation-amount-invalid "Amount is not valid"
|
||||||
|
:validation-amount-invalid-number "Amount is not a valid number"
|
||||||
:validation-amount-is-too-precise "Amount is too precise. The smallest unit you can send is 1 Wei (1x10^-18 ETH)"
|
:validation-amount-is-too-precise "Amount is too precise. The smallest unit you can send is 1 Wei (1x10^-18 ETH)"
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
[reagent.core :as reagent]
|
[reagent.core :as reagent]
|
||||||
[status-im.components.icons.vector-icons :as vector-icons]
|
[status-im.components.icons.vector-icons :as vector-icons]
|
||||||
[status-im.components.animation :as animation]
|
[status-im.components.animation :as animation]
|
||||||
|
[status-im.utils.money :as money]
|
||||||
[status-im.utils.platform :as platform]
|
[status-im.utils.platform :as platform]
|
||||||
[status-im.ui.screens.wallet.components.animations :as animations]))
|
[status-im.ui.screens.wallet.components.animations :as animations]))
|
||||||
|
|
||||||
|
@ -73,16 +74,18 @@
|
||||||
|
|
||||||
;;TODO (andrey) this should be choose component with the list of wallets
|
;;TODO (andrey) this should be choose component with the list of wallets
|
||||||
(views/defview choose-wallet [& [style]]
|
(views/defview choose-wallet [& [style]]
|
||||||
(views/letsubs [eth-balance [:eth-balance]]
|
(views/letsubs [balance [:balance]]
|
||||||
[react/view
|
[react/view
|
||||||
[react/text {:style styles/label} (i18n/label :t/wallet)]
|
[react/text {:style styles/label} (i18n/label :t/wallet)]
|
||||||
[react/view (merge styles/wallet-container
|
[react/view (merge styles/wallet-container
|
||||||
style)
|
style)
|
||||||
[react/text {:style styles/wallet-name} "Main wallet"]
|
[react/text {:style styles/wallet-name} (i18n/label :t/main-wallet)]
|
||||||
[react/text {:style styles/wallet-value
|
[react/text {:style styles/wallet-value
|
||||||
:number-of-lines 1
|
:number-of-lines 1
|
||||||
:ellipsizeMode :middle}
|
:ellipsizeMode :middle}
|
||||||
(str eth-balance " ETH")]]]))
|
(if balance
|
||||||
|
(money/wei->str :eth balance)
|
||||||
|
"...")]]]))
|
||||||
|
|
||||||
(defn network-label
|
(defn network-label
|
||||||
([n] (network-label [{} n]))
|
([n] (network-label [{} n]))
|
||||||
|
|
|
@ -24,9 +24,12 @@
|
||||||
(let [amount' (string/replace amount #"," ".")
|
(let [amount' (string/replace amount #"," ".")
|
||||||
amount-splited (string/split amount' #"[.]")]
|
amount-splited (string/split amount' #"[.]")]
|
||||||
(cond
|
(cond
|
||||||
(or (nil? amount) (= amount "") (= amount "0") (re-matches #"0[,.]0*$" amount))
|
(or (nil? amount) (= amount "") (re-matches #"0[,.]0*$" amount))
|
||||||
nil
|
nil
|
||||||
|
|
||||||
|
(= amount "0")
|
||||||
|
(i18n/label :t/validation-amount-invalid)
|
||||||
|
|
||||||
(or (js/isNaN (js/parseFloat amount'))
|
(or (js/isNaN (js/parseFloat amount'))
|
||||||
(try (when (<= (.toWei web3 amount' "ether") 0) true)
|
(try (when (<= (.toWei web3 amount' "ether") 0) true)
|
||||||
(catch :default err true)))
|
(catch :default err true)))
|
||||||
|
|
|
@ -12,11 +12,13 @@
|
||||||
[status-im.i18n :as i18n]
|
[status-im.i18n :as i18n]
|
||||||
[status-im.react-native.resources :as resources]
|
[status-im.react-native.resources :as resources]
|
||||||
[status-im.utils.config :as config]
|
[status-im.utils.config :as config]
|
||||||
[status-im.utils.utils :as utils]
|
[status-im.utils.money :as money]
|
||||||
[status-im.utils.platform :as platform]
|
[status-im.utils.platform :as platform]
|
||||||
|
[status-im.utils.utils :as utils]
|
||||||
[status-im.ui.screens.wallet.main.styles :as styles]
|
[status-im.ui.screens.wallet.main.styles :as styles]
|
||||||
[status-im.ui.screens.wallet.styles :as wallet.styles]
|
[status-im.ui.screens.wallet.styles :as wallet.styles]
|
||||||
[status-im.components.styles :as components.styles]
|
[status-im.components.styles :as components.styles]
|
||||||
|
[status-im.components.button.styles :as button.styles]
|
||||||
[status-im.ui.screens.wallet.views :as wallet.views]))
|
[status-im.ui.screens.wallet.views :as wallet.views]))
|
||||||
|
|
||||||
(defn- show-not-implemented! []
|
(defn- show-not-implemented! []
|
||||||
|
@ -59,6 +61,11 @@
|
||||||
(str (when pos-change? "+") change "%")
|
(str (when pos-change? "+") change "%")
|
||||||
"-%")]]))
|
"-%")]]))
|
||||||
|
|
||||||
|
(defn- wallet-send []
|
||||||
|
(rf/dispatch [:navigate-to :wallet-send-transaction])
|
||||||
|
(when platform/android?
|
||||||
|
(rf/dispatch [:request-permissions [:camera]])))
|
||||||
|
|
||||||
(defn main-section [usd-value change error-message]
|
(defn main-section [usd-value change error-message]
|
||||||
[react/view {:style styles/main-section}
|
[react/view {:style styles/main-section}
|
||||||
(when error-message
|
(when error-message
|
||||||
|
@ -71,17 +78,13 @@
|
||||||
[react/text {:style styles/value-variation-title}
|
[react/text {:style styles/value-variation-title}
|
||||||
(i18n/label :t/wallet-total-value)]
|
(i18n/label :t/wallet-total-value)]
|
||||||
[change-display change]]
|
[change-display change]]
|
||||||
[btn/buttons {:style styles/buttons :button-text-style styles/main-button-text}
|
[react/view {:style (merge button.styles/buttons-container styles/buttons) :button-text-style styles/main-button-text}
|
||||||
[{:text (i18n/label :t/wallet-send)
|
[btn/button {:on-press wallet-send :style (button.styles/button-bar :first)}
|
||||||
:on-press #(do (rf/dispatch [:navigate-to :wallet-send-transaction])
|
(i18n/label :t/wallet-send)]
|
||||||
(when platform/android?
|
[btn/button {:on-press #(rf/dispatch [:navigate-to :wallet-request-transaction]) :style (button.styles/button-bar :other)}
|
||||||
(rf/dispatch [:request-permissions [:camera]])))
|
(i18n/label :t/wallet-request)]
|
||||||
:disabled? (not config/wallet-wip-enabled?)}
|
[btn/button {:disabled? true :style (button.styles/button-bar :last)}
|
||||||
{:text (i18n/label :t/wallet-request)
|
(i18n/label :t/wallet-exchange)]]]])
|
||||||
:on-press #(rf/dispatch [:navigate-to :wallet-request-transaction])
|
|
||||||
:disabled? (not config/wallet-wip-enabled?)}
|
|
||||||
{:text (i18n/label :t/wallet-exchange)
|
|
||||||
:disabled? true}]]]])
|
|
||||||
|
|
||||||
(defn- token->image [id]
|
(defn- token->image [id]
|
||||||
(case id
|
(case id
|
||||||
|
@ -115,14 +118,14 @@
|
||||||
(let [{:keys [source style]} (token->image id)]
|
(let [{:keys [source style]} (token->image id)]
|
||||||
[list/item-image source style])
|
[list/item-image source style])
|
||||||
[react/view {:style styles/asset-item-value-container}
|
[react/view {:style styles/asset-item-value-container}
|
||||||
[react/text {:style styles/asset-item-value} (str amount)]
|
[react/text {:style styles/asset-item-value} (str (money/wei->ether amount))]
|
||||||
[react/text {:style styles/asset-item-currency
|
[react/text {:style styles/asset-item-currency
|
||||||
:uppercase? true}
|
:uppercase? true}
|
||||||
id]]]]
|
id]]]]
|
||||||
[add-asset]))
|
[add-asset]))
|
||||||
|
|
||||||
(defn asset-section [eth prices-loading? balance-loading?]
|
(defn asset-section [balance prices-loading? balance-loading?]
|
||||||
(let [assets [{:id "eth" :currency :eth :amount eth}]]
|
(let [assets [{:id "eth" :currency :eth :amount balance}]]
|
||||||
[react/view {:style styles/asset-section}
|
[react/view {:style styles/asset-section}
|
||||||
[react/text {:style styles/asset-section-title} (i18n/label :t/wallet-assets)]
|
[react/text {:style styles/asset-section-title} (i18n/label :t/wallet-assets)]
|
||||||
[list/flat-list
|
[list/flat-list
|
||||||
|
@ -132,7 +135,7 @@
|
||||||
:refreshing (boolean (or prices-loading? balance-loading?))}]]))
|
:refreshing (boolean (or prices-loading? balance-loading?))}]]))
|
||||||
|
|
||||||
(defview wallet []
|
(defview wallet []
|
||||||
(letsubs [eth-balance [:eth-balance]
|
(letsubs [balance [:balance]
|
||||||
portfolio-value [:portfolio-value]
|
portfolio-value [:portfolio-value]
|
||||||
portfolio-change [:portfolio-change]
|
portfolio-change [:portfolio-change]
|
||||||
prices-loading? [:prices-loading?]
|
prices-loading? [:prices-loading?]
|
||||||
|
@ -142,4 +145,4 @@
|
||||||
[toolbar-view]
|
[toolbar-view]
|
||||||
[react/view components.styles/flex
|
[react/view components.styles/flex
|
||||||
[main-section portfolio-value portfolio-change error-message]
|
[main-section portfolio-value portfolio-change error-message]
|
||||||
[asset-section eth-balance prices-loading? balance-loading?]]]))
|
[asset-section balance prices-loading? balance-loading?]]]))
|
||||||
|
|
|
@ -99,7 +99,7 @@
|
||||||
:wallet/keys [send-transaction]
|
:wallet/keys [send-transaction]
|
||||||
:accounts/keys [accounts current-account-id] :as db} :db} [_ later?]]
|
:accounts/keys [accounts current-account-id] :as db} :db} [_ later?]]
|
||||||
(let [{:keys [amount transaction-id password]} send-transaction
|
(let [{:keys [amount transaction-id password]} send-transaction
|
||||||
amount' (money/to-wei (string/replace amount #"," "."))]
|
amount-in-wei (money/to-wei (string/replace amount #"," "."))]
|
||||||
(if transaction-id
|
(if transaction-id
|
||||||
{::accept-transaction {:id transaction-id
|
{::accept-transaction {:id transaction-id
|
||||||
:password password
|
:password password
|
||||||
|
@ -110,7 +110,7 @@
|
||||||
::send-transaction {:web3 web3
|
::send-transaction {:web3 web3
|
||||||
:from (get-in accounts [current-account-id :address])
|
:from (get-in accounts [current-account-id :address])
|
||||||
:to (:to-address send-transaction)
|
:to (:to-address send-transaction)
|
||||||
:value amount'}}))))
|
:value amount-in-wei}}))))
|
||||||
|
|
||||||
(handlers/register-handler-fx
|
(handlers/register-handler-fx
|
||||||
:wallet/discard-transaction
|
:wallet/discard-transaction
|
||||||
|
|
|
@ -1,27 +1,24 @@
|
||||||
(ns status-im.ui.screens.wallet.send.views
|
(ns status-im.ui.screens.wallet.send.views
|
||||||
(:require-macros [status-im.utils.views :refer [defview letsubs]])
|
(:require-macros [status-im.utils.views :refer [defview letsubs]])
|
||||||
(:require [clojure.string :as str]
|
(:require [clojure.string :as string]
|
||||||
[status-im.components.react :as react]
|
|
||||||
[re-frame.core :as re-frame]
|
[re-frame.core :as re-frame]
|
||||||
[status-im.components.button.view :as button]
|
[status-im.components.animation :as animation]
|
||||||
|
[status-im.components.icons.vector-icons :as vector-icons]
|
||||||
|
[status-im.components.react :as react]
|
||||||
[status-im.components.status-bar :as status-bar]
|
[status-im.components.status-bar :as status-bar]
|
||||||
|
[status-im.components.styles :as components.styles]
|
||||||
[status-im.components.toolbar-new.actions :as act]
|
[status-im.components.toolbar-new.actions :as act]
|
||||||
[status-im.components.toolbar-new.view :as toolbar]
|
[status-im.components.toolbar-new.view :as toolbar]
|
||||||
[status-im.components.camera :as camera]
|
[status-im.components.camera :as camera]
|
||||||
[status-im.utils.utils :as utils]
|
[status-im.utils.utils :as utils]
|
||||||
[status-im.i18n :as i18n]
|
[status-im.i18n :as i18n]
|
||||||
[status-im.ui.screens.wallet.send.styles :as send.styles]
|
[status-im.utils.money :as money]
|
||||||
[status-im.components.icons.vector-icons :as vector-icons]
|
|
||||||
[reagent.core :as r]
|
|
||||||
[status-im.utils.platform :as platform]
|
[status-im.utils.platform :as platform]
|
||||||
[status-im.ui.screens.wallet.request.styles :as request.styles]
|
[status-im.ui.screens.wallet.request.styles :as request.styles]
|
||||||
[status-im.ui.screens.wallet.send.styles :as styles]
|
|
||||||
[status-im.ui.screens.wallet.components.views :as components]
|
[status-im.ui.screens.wallet.components.views :as components]
|
||||||
[status-im.components.styles :as components.styles]
|
|
||||||
[status-im.components.icons.vector-icons :as vi]
|
|
||||||
[status-im.components.animation :as animation]
|
|
||||||
[status-im.ui.screens.wallet.styles :as wallet.styles]
|
[status-im.ui.screens.wallet.styles :as wallet.styles]
|
||||||
[status-im.ui.screens.wallet.send.animations :as send.animations]))
|
[status-im.ui.screens.wallet.send.animations :as send.animations]
|
||||||
|
[status-im.ui.screens.wallet.send.styles :as send.styles]))
|
||||||
|
|
||||||
(defn toolbar-view [signing?]
|
(defn toolbar-view [signing?]
|
||||||
[toolbar/toolbar2 {:style wallet.styles/toolbar}
|
[toolbar/toolbar2 {:style wallet.styles/toolbar}
|
||||||
|
@ -45,24 +42,22 @@
|
||||||
bottom-value (animation/create-value -250)
|
bottom-value (animation/create-value -250)
|
||||||
opacity-value (animation/create-value 0)]
|
opacity-value (animation/create-value 0)]
|
||||||
{:component-did-mount #(send.animations/animate-sign-panel opacity-value bottom-value)}
|
{:component-did-mount #(send.animations/animate-sign-panel opacity-value bottom-value)}
|
||||||
[react/animated-view {:style (styles/animated-sign-panel bottom-value)}
|
[react/animated-view {:style (send.styles/animated-sign-panel bottom-value)}
|
||||||
[react/animated-view {:style (styles/sign-panel opacity-value)}
|
[react/animated-view {:style (send.styles/sign-panel opacity-value)}
|
||||||
[react/view styles/signing-phrase-container
|
[react/view send.styles/signing-phrase-container
|
||||||
[react/text {:style styles/signing-phrase} signing-phrase]]
|
[react/text {:style send.styles/signing-phrase} signing-phrase]]
|
||||||
[react/text {:style styles/signing-phrase-description} (i18n/label :t/signing-phrase-description)]
|
[react/text {:style send.styles/signing-phrase-description} (i18n/label :t/signing-phrase-description)]
|
||||||
[react/view styles/password-container
|
[react/view send.styles/password-container
|
||||||
[react/text-input
|
[react/text-input
|
||||||
{:auto-focus true
|
{:auto-focus true
|
||||||
:secure-text-entry true
|
:secure-text-entry true
|
||||||
:placeholder (i18n/label :t/enter-password)
|
:placeholder (i18n/label :t/enter-password)
|
||||||
:placeholder-text-color "#939ba1"
|
:placeholder-text-color "#939ba1"
|
||||||
:on-change-text #(do
|
:on-change-text #(re-frame/dispatch [:set-in [:wallet/send-transaction :password] %])
|
||||||
(re-frame/dispatch [:set-in [:wallet/send-transaction :password] %]))
|
:style send.styles/password}]]]
|
||||||
:style styles/password}]]]
|
|
||||||
(when wrong-password?
|
(when wrong-password?
|
||||||
[components/tooltip (i18n/label :t/wrong-password)])]))
|
[components/tooltip (i18n/label :t/wrong-password)])]))
|
||||||
|
|
||||||
|
|
||||||
(defview signing-buttons []
|
(defview signing-buttons []
|
||||||
(letsubs [sign-enabled? [:wallet.send/sign-password-enabled?]]
|
(letsubs [sign-enabled? [:wallet.send/sign-password-enabled?]]
|
||||||
[react/view wallet.styles/buttons-container
|
[react/view wallet.styles/buttons-container
|
||||||
|
@ -73,27 +68,39 @@
|
||||||
[react/touchable-highlight {:on-press #(re-frame/dispatch [:wallet/sign-transaction])}
|
[react/touchable-highlight {:on-press #(re-frame/dispatch [:wallet/sign-transaction])}
|
||||||
[react/view (wallet.styles/button-container sign-enabled?)
|
[react/view (wallet.styles/button-container sign-enabled?)
|
||||||
[components/button-text (i18n/label :t/transactions-sign-transaction)]
|
[components/button-text (i18n/label :t/transactions-sign-transaction)]
|
||||||
[vi/icon :icons/forward {:color :white :container-style wallet.styles/forward-icon-container}]]]]))
|
[vector-icons/icon :icons/forward {:color :white :container-style wallet.styles/forward-icon-container}]]]]))
|
||||||
|
|
||||||
(defview sign-buttons []
|
(defn sign-enabled? [amount-error to-address amount]
|
||||||
(letsubs [sign-enabled? [:wallet.send/sign-enabled?]]
|
(and
|
||||||
|
(nil? amount-error)
|
||||||
|
(not (nil? to-address)) (not= to-address "")
|
||||||
|
(not (nil? amount)) (not= amount "")))
|
||||||
|
|
||||||
|
(defn- sign-buttons [amount-error to-address amount sufficient-funds?]
|
||||||
|
(let [sign-enabled? (sign-enabled? amount-error to-address amount)
|
||||||
|
immediate-sign-enabled? (and sign-enabled? sufficient-funds?)]
|
||||||
[react/view wallet.styles/buttons-container
|
[react/view wallet.styles/buttons-container
|
||||||
(when sign-enabled?
|
(when sign-enabled?
|
||||||
[react/touchable-highlight {:on-press sign-later}
|
[react/touchable-highlight {:on-press sign-later}
|
||||||
[react/view (wallet.styles/button-container sign-enabled?)
|
[react/view (wallet.styles/button-container sign-enabled?)
|
||||||
[components/button-text (i18n/label :t/transactions-sign-later)]]])
|
[components/button-text (i18n/label :t/transactions-sign-later)]]])
|
||||||
[react/view components.styles/flex]
|
[react/view components.styles/flex]
|
||||||
[react/touchable-highlight {:on-press (when sign-enabled? #(re-frame/dispatch [:set-in [:wallet/send-transaction :signing?] true]))}
|
[react/touchable-highlight {:on-press (when immediate-sign-enabled? #(re-frame/dispatch [:set-in [:wallet/send-transaction :signing?] true]))}
|
||||||
[react/view (wallet.styles/button-container sign-enabled?)
|
[react/view (wallet.styles/button-container immediate-sign-enabled?)
|
||||||
[components/button-text (i18n/label :t/transactions-sign-transaction)]
|
[components/button-text (i18n/label :t/transactions-sign-transaction)]
|
||||||
[vi/icon :icons/forward {:color :white :container-style wallet.styles/forward-icon-container}]]]]))
|
[vector-icons/icon :icons/forward {:color :white :container-style wallet.styles/forward-icon-container}]]]]))
|
||||||
|
|
||||||
|
(defn- sufficient-funds? [amount balance]
|
||||||
|
(<= amount (money/wei->ether balance)))
|
||||||
|
|
||||||
(defview send-transaction []
|
(defview send-transaction []
|
||||||
(letsubs [amount [:get-in [:wallet/send-transaction :amount]]
|
(letsubs [balance [:balance]
|
||||||
|
amount [:get-in [:wallet/send-transaction :amount]]
|
||||||
amount-error [:get-in [:wallet/send-transaction :amount-error]]
|
amount-error [:get-in [:wallet/send-transaction :amount-error]]
|
||||||
signing? [:get-in [:wallet/send-transaction :signing?]]
|
signing? [:get-in [:wallet/send-transaction :signing?]]
|
||||||
to-address [:get-in [:wallet/send-transaction :to-address]]
|
to-address [:get-in [:wallet/send-transaction :to-address]]
|
||||||
to-name [:get-in [:wallet/send-transaction :to-name]]]
|
to-name [:get-in [:wallet/send-transaction :to-name]]]
|
||||||
|
(let [sufficient-funds? (sufficient-funds? amount balance)]
|
||||||
[react/keyboard-avoiding-view wallet.styles/wallet-modal-container
|
[react/keyboard-avoiding-view wallet.styles/wallet-modal-container
|
||||||
[react/view components.styles/flex
|
[react/view components.styles/flex
|
||||||
[status-bar/status-bar {:type :wallet}]
|
[status-bar/status-bar {:type :wallet}]
|
||||||
|
@ -108,17 +115,17 @@
|
||||||
[components/choose-wallet]]
|
[components/choose-wallet]]
|
||||||
[react/view wallet.styles/amount-container
|
[react/view wallet.styles/amount-container
|
||||||
[components/amount-input
|
[components/amount-input
|
||||||
{:error amount-error
|
{:error (or amount-error (when-not sufficient-funds? (i18n/label :t/wallet-insufficient-funds)))
|
||||||
:input-options {:auto-focus true
|
:input-options {:auto-focus true
|
||||||
:default-value amount
|
:default-value amount
|
||||||
:on-change-text #(do
|
:on-change-text #(let [value (string/trim %)]
|
||||||
(re-frame/dispatch [:set-in [:wallet/send-transaction :amount] %])
|
(re-frame/dispatch [:set-in [:wallet/send-transaction :amount] value])
|
||||||
(re-frame/dispatch [:wallet-validate-amount]))}}]
|
(re-frame/dispatch [:wallet-validate-amount]))}}]
|
||||||
[react/view wallet.styles/choose-currency-container
|
[react/view wallet.styles/choose-currency-container
|
||||||
[components/choose-currency wallet.styles/choose-currency]]]]]
|
[components/choose-currency wallet.styles/choose-currency]]]]]
|
||||||
[components/separator]
|
[components/separator]
|
||||||
(if signing?
|
(if signing?
|
||||||
[signing-buttons]
|
[signing-buttons]
|
||||||
[sign-buttons])
|
[sign-buttons amount-error to-address amount sufficient-funds?])
|
||||||
(when signing?
|
(when signing?
|
||||||
[sign-panel])]]))
|
[sign-panel])]])))
|
|
@ -25,13 +25,6 @@
|
||||||
(or (get-in wallet [:errors :balance-update])
|
(or (get-in wallet [:errors :balance-update])
|
||||||
(get-in wallet [:errors :prices-update]))))
|
(get-in wallet [:errors :prices-update]))))
|
||||||
|
|
||||||
(reg-sub :eth-balance
|
|
||||||
:<- [:balance]
|
|
||||||
(fn [balance]
|
|
||||||
(if balance
|
|
||||||
(money/wei->ether balance)
|
|
||||||
"...")))
|
|
||||||
|
|
||||||
(reg-sub :portfolio-value
|
(reg-sub :portfolio-value
|
||||||
:<- [:balance]
|
:<- [:balance]
|
||||||
:<- [:price]
|
:<- [:price]
|
||||||
|
|
|
@ -92,50 +92,50 @@
|
||||||
|
|
||||||
;; transaction details
|
;; transaction details
|
||||||
|
|
||||||
(def transaction-details-row
|
(def details-row
|
||||||
{:flex-direction :row
|
{:flex-direction :row
|
||||||
:margin-vertical 5})
|
:margin-vertical 5})
|
||||||
|
|
||||||
(def transaction-details-item-label
|
(def details-item-label
|
||||||
{:flex 1
|
{:flex 1
|
||||||
:margin-right 10
|
:margin-right 10
|
||||||
:color styles/color-gray4
|
:color styles/color-gray4
|
||||||
:font-size 14})
|
:font-size 14})
|
||||||
|
|
||||||
(def transaction-details-item-value-wrapper
|
(def details-item-value-wrapper
|
||||||
{:flex 5})
|
{:flex 5})
|
||||||
|
|
||||||
(def transaction-details-item-value
|
(def details-item-value
|
||||||
{:font-size 14
|
{:font-size 14
|
||||||
:color styles/color-black})
|
:color styles/color-black})
|
||||||
|
|
||||||
(def transaction-details-item-extra-value
|
(def details-item-extra-value
|
||||||
{:font-size 14
|
{:font-size 14
|
||||||
:color styles/color-gray4})
|
:color styles/color-gray4})
|
||||||
|
|
||||||
(def transaction-details-header
|
(def details-header
|
||||||
{:margin-horizontal 16
|
{:margin-horizontal 16
|
||||||
:margin-top 10
|
:margin-top 10
|
||||||
:flex-direction :row})
|
:flex-direction :row})
|
||||||
|
|
||||||
(def transaction-details-header-icon
|
(def details-header-icon
|
||||||
{:margin-vertical 7})
|
{:margin-vertical 7})
|
||||||
|
|
||||||
(def transaction-details-header-infos
|
(def details-header-infos
|
||||||
{:flex 1
|
{:flex 1
|
||||||
:flex-direction :column
|
:flex-direction :column
|
||||||
:margin-left 12
|
:margin-left 12
|
||||||
:margin-vertical 7})
|
:margin-vertical 7})
|
||||||
|
|
||||||
(def transaction-details-header-value
|
(def details-header-value
|
||||||
{:font-size 16
|
{:font-size 16
|
||||||
:color styles/color-black})
|
:color styles/color-black})
|
||||||
|
|
||||||
(def transaction-details-header-date
|
(def details-header-date
|
||||||
{:font-size 14
|
{:font-size 14
|
||||||
:color styles/color-gray4})
|
:color styles/color-gray4})
|
||||||
|
|
||||||
(def transaction-details-block
|
(def details-block
|
||||||
{:margin-horizontal 16})
|
{:margin-horizontal 16})
|
||||||
|
|
||||||
(def progress-bar
|
(def progress-bar
|
||||||
|
@ -152,17 +152,17 @@
|
||||||
:background-color styles/color-blue2
|
:background-color styles/color-blue2
|
||||||
:opacity 0.30})
|
:opacity 0.30})
|
||||||
|
|
||||||
(def transaction-details-confirmations-count
|
(def details-confirmations-count
|
||||||
{:color styles/color-black
|
{:color styles/color-black
|
||||||
:font-size 15
|
:font-size 15
|
||||||
:margin-vertical 2})
|
:margin-vertical 2})
|
||||||
|
|
||||||
(def transaction-details-confirmations-helper-text
|
(def details-confirmations-helper-text
|
||||||
{:color styles/color-gray4
|
{:color styles/color-gray4
|
||||||
:font-size 14
|
:font-size 14
|
||||||
:margin-vertical 2})
|
:margin-vertical 2})
|
||||||
|
|
||||||
(def transaction-details-separator
|
(def details-separator
|
||||||
{:background-color styles/color-light-gray3
|
{:background-color styles/color-light-gray3
|
||||||
:height 1
|
:height 1
|
||||||
:margin-vertical 10})
|
:margin-vertical 10})
|
||||||
|
|
|
@ -26,12 +26,11 @@
|
||||||
(group-by :type (vals transactions))))
|
(group-by :type (vals transactions))))
|
||||||
|
|
||||||
(defn format-unsigned-transaction [{:keys [message-id gas-price] :as transaction}]
|
(defn format-unsigned-transaction [{:keys [message-id gas-price] :as transaction}]
|
||||||
(-> transaction
|
(assoc transaction
|
||||||
(update :value money/wei->ether)
|
:type :unsigned
|
||||||
(assoc :type :unsigned
|
|
||||||
:confirmations 0
|
:confirmations 0
|
||||||
:symbol "ETH"
|
:symbol "ETH"
|
||||||
:hash message-id)))
|
:hash message-id))
|
||||||
|
|
||||||
(reg-sub :wallet.transactions/unsigned-transactions
|
(reg-sub :wallet.transactions/unsigned-transactions
|
||||||
:<- [:transactions]
|
:<- [:transactions]
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
[status-im.i18n :as i18n]
|
[status-im.i18n :as i18n]
|
||||||
[status-im.ui.screens.wallet.transactions.styles :as transactions.styles]
|
[status-im.ui.screens.wallet.transactions.styles :as transactions.styles]
|
||||||
[status-im.ui.screens.wallet.views :as wallet.views]
|
[status-im.ui.screens.wallet.views :as wallet.views]
|
||||||
|
[status-im.utils.money :as money]
|
||||||
[status-im.utils.utils :as utils])
|
[status-im.utils.utils :as utils])
|
||||||
(:require-macros [status-im.utils.views :refer [defview letsubs]]))
|
(:require-macros [status-im.utils.views :refer [defview letsubs]]))
|
||||||
|
|
||||||
|
@ -98,7 +99,7 @@
|
||||||
[list/item
|
[list/item
|
||||||
[list/item-icon (transaction-type->icon (keyword type))]
|
[list/item-icon (transaction-type->icon (keyword type))]
|
||||||
[list/item-content
|
[list/item-content
|
||||||
(str value " " symbol)
|
(money/wei->str :eth value)
|
||||||
(if (inbound? type)
|
(if (inbound? type)
|
||||||
(str (i18n/label :t/from) " " from)
|
(str (i18n/label :t/from) " " from)
|
||||||
(str (i18n/label :t/to) " " to))
|
(str (i18n/label :t/to) " " to))
|
||||||
|
@ -205,66 +206,70 @@
|
||||||
[toolbar-view view-id unsigned-transactions-count]
|
[toolbar-view view-id unsigned-transactions-count]
|
||||||
[main-section view-id tabs]])))
|
[main-section view-id tabs]])))
|
||||||
|
|
||||||
(defn transaction-details-header [{:keys [value date type]}]
|
(defn- pretty-print-asset [symbol amount]
|
||||||
[react/view {:style transactions.styles/transaction-details-header}
|
(case symbol
|
||||||
[react/view {:style transactions.styles/transaction-details-header-icon}
|
"ETH" (if amount (money/wei->str :eth amount) "...")))
|
||||||
|
|
||||||
|
(defn details-header [{:keys [value date type symbol]}]
|
||||||
|
[react/view {:style transactions.styles/details-header}
|
||||||
|
[react/view {:style transactions.styles/details-header-icon}
|
||||||
[list/item-icon (transaction-type->icon type)]]
|
[list/item-icon (transaction-type->icon type)]]
|
||||||
[react/view {:style transactions.styles/transaction-details-header-infos}
|
[react/view {:style transactions.styles/details-header-infos}
|
||||||
[react/text {:style transactions.styles/transaction-details-header-value} (str value " ETH")]
|
[react/text {:style transactions.styles/details-header-value} (pretty-print-asset symbol value)]
|
||||||
[react/text {:style transactions.styles/transaction-details-header-date} date]]])
|
[react/text {:style transactions.styles/details-header-date} date]]])
|
||||||
|
|
||||||
(defn progress-bar [progress]
|
(defn progress-bar [progress]
|
||||||
[react/view {:style transactions.styles/progress-bar}
|
[react/view {:style transactions.styles/progress-bar}
|
||||||
[react/view {:style (transactions.styles/progress-bar-done progress)}]
|
[react/view {:style (transactions.styles/progress-bar-done progress)}]
|
||||||
[react/view {:style (transactions.styles/progress-bar-todo (- 100 progress))}]])
|
[react/view {:style (transactions.styles/progress-bar-todo (- 100 progress))}]])
|
||||||
|
|
||||||
(defn transaction-details-confirmations [confirmations confirmations-progress]
|
(defn details-confirmations [confirmations confirmations-progress]
|
||||||
[react/view {:style transactions.styles/transaction-details-block}
|
[react/view {:style transactions.styles/details-block}
|
||||||
[progress-bar confirmations-progress]
|
[progress-bar confirmations-progress]
|
||||||
[react/text {:style transactions.styles/transaction-details-confirmations-count}
|
[react/text {:style transactions.styles/details-confirmations-count}
|
||||||
(str confirmations " " (i18n/label :t/confirmations))]
|
(str confirmations " " (i18n/label :t/confirmations))]
|
||||||
[react/text {:style transactions.styles/transaction-details-confirmations-helper-text}
|
[react/text {:style transactions.styles/details-confirmations-helper-text}
|
||||||
(i18n/label :t/confirmations-helper-text)]])
|
(i18n/label :t/confirmations-helper-text)]])
|
||||||
|
|
||||||
(defn transaction-details-list-row
|
(defn details-list-row
|
||||||
([label value]
|
([label value]
|
||||||
(transaction-details-list-row label value nil))
|
(details-list-row label value nil))
|
||||||
([label value extra-value]
|
([label value extra-value]
|
||||||
[react/view {:style transactions.styles/transaction-details-row}
|
[react/view {:style transactions.styles/details-row}
|
||||||
[react/text {:style transactions.styles/transaction-details-item-label} (i18n/label label)]
|
[react/text {:style transactions.styles/details-item-label} (i18n/label label)]
|
||||||
[react/view {:style transactions.styles/transaction-details-item-value-wrapper}
|
[react/view {:style transactions.styles/details-item-value-wrapper}
|
||||||
[react/text {:style transactions.styles/transaction-details-item-value} (str value)]
|
[react/text {:style transactions.styles/details-item-value} (str value)]
|
||||||
[react/text {:style transactions.styles/transaction-details-item-extra-value} (str extra-value)]]]))
|
[react/text {:style transactions.styles/details-item-extra-value} (str extra-value)]]]))
|
||||||
|
|
||||||
(defn transaction-details-list [{:keys [block hash from from-wallet to to-wallet gas-limit gas-price-gwei gas-price-eth gas-used cost nonce data]}]
|
(defn details-list [{:keys [block hash from from-wallet to to-wallet gas-limit gas-price-gwei gas-price-eth gas-used cost nonce data]}]
|
||||||
[react/view {:style transactions.styles/transaction-details-block}
|
[react/view {:style transactions.styles/details-block}
|
||||||
[transaction-details-list-row :t/block block]
|
[details-list-row :t/block block]
|
||||||
[transaction-details-list-row :t/hash hash]
|
[details-list-row :t/hash hash]
|
||||||
[transaction-details-list-row :t/from (or from-wallet from) (when from-wallet from)]
|
[details-list-row :t/from (or from-wallet from) (when from-wallet from)]
|
||||||
[transaction-details-list-row :t/to (or to-wallet to) (when to-wallet to)]
|
[details-list-row :t/to (or to-wallet to) (when to-wallet to)]
|
||||||
[transaction-details-list-row :t/gas-limit gas-limit]
|
[details-list-row :t/gas-limit gas-limit]
|
||||||
[transaction-details-list-row :t/gas-price gas-price-gwei gas-price-eth]
|
[details-list-row :t/gas-price gas-price-gwei gas-price-eth]
|
||||||
[transaction-details-list-row :t/gas-used gas-used]
|
[details-list-row :t/gas-used gas-used]
|
||||||
[transaction-details-list-row :t/cost-fee cost]
|
[details-list-row :t/cost-fee cost]
|
||||||
[transaction-details-list-row :t/nonce nonce]
|
[details-list-row :t/nonce nonce]
|
||||||
[transaction-details-list-row :t/data data]])
|
[details-list-row :t/data data]])
|
||||||
|
|
||||||
(defn details-action [hash url]
|
(defn details-action [hash url]
|
||||||
[(actions/opts [{:text (i18n/label :t/copy-transaction-hash) :value #(react/copy-to-clipboard hash)}
|
[(actions/opts [{:text (i18n/label :t/copy-transaction-hash) :value #(react/copy-to-clipboard hash)}
|
||||||
{:text (i18n/label :t/open-on-etherscan) :value #(.openURL react/linking url)}])])
|
{:text (i18n/label :t/open-on-etherscan) :value #(.openURL react/linking url)}])])
|
||||||
|
|
||||||
(defview transaction-details []
|
(defview transaction-details []
|
||||||
(letsubs [{:keys [hash url type] :as transaction-details} [:wallet.transactions/transaction-details]
|
(letsubs [{:keys [hash url type] :as transactions} [:wallet.transactions/details]
|
||||||
confirmations [:wallet.transactions.details/confirmations]
|
confirmations [:wallet.transactions.details/confirmations]
|
||||||
confirmations-progress [:wallet.transactions.details/confirmations-progress]]
|
confirmations-progress [:wallet.transactions.details/confirmations-progress]]
|
||||||
[react/view {:style styles/flex}
|
[react/view {:style styles/flex}
|
||||||
[status-bar/status-bar]
|
[status-bar/status-bar]
|
||||||
[toolbar/toolbar2 {}
|
[toolbar/toolbar2 {}
|
||||||
toolbar/default-nav-back
|
toolbar/default-nav-back
|
||||||
[toolbar/content-title (i18n/label :t/transaction-details)]
|
[toolbar/content-title (i18n/label :t/details)]
|
||||||
[toolbar/actions (details-action hash url)]]
|
[toolbar/actions (details-action hash url)]]
|
||||||
[react/scroll-view {:style transactions.styles/main-section}
|
[react/scroll-view {:style transactions.styles/main-section}
|
||||||
[transaction-details-header transaction-details]
|
[details-header transactions]
|
||||||
[transaction-details-confirmations confirmations confirmations-progress]
|
[details-confirmations confirmations confirmations-progress]
|
||||||
[react/view {:style transactions.styles/transaction-details-separator}]
|
[react/view {:style transactions.styles/details-separator}]
|
||||||
[transaction-details-list transaction-details]]]))
|
[details-list transactions]]]))
|
||||||
|
|
|
@ -10,7 +10,6 @@
|
||||||
(defn enabled? [v] (= "1" v))
|
(defn enabled? [v] (= "1" v))
|
||||||
|
|
||||||
(def testfairy-enabled? (enabled? (get-config :TESTFAIRY_ENABLED)))
|
(def testfairy-enabled? (enabled? (get-config :TESTFAIRY_ENABLED)))
|
||||||
(def wallet-wip-enabled? (enabled? (get-config :WALLET_WIP_ENABLED 0)))
|
|
||||||
(def notifications-wip-enabled? (enabled? (get-config :NOTIFICATIONS_WIP_ENABLED 0)))
|
(def notifications-wip-enabled? (enabled? (get-config :NOTIFICATIONS_WIP_ENABLED 0)))
|
||||||
(def stub-status-go? (enabled? (get-config :STUB_STATUS_GO 0)))
|
(def stub-status-go? (enabled? (get-config :STUB_STATUS_GO 0)))
|
||||||
(def network-switching-enabled? (enabled? (get-config :NETWORK_SWITCHING 0)))
|
(def network-switching-enabled? (enabled? (get-config :NETWORK_SWITCHING 0)))
|
||||||
|
|
|
@ -18,9 +18,9 @@
|
||||||
(str "https://" network-subdomain ".etherscan.io/api?module=account&action=txlist&address=0x"
|
(str "https://" network-subdomain ".etherscan.io/api?module=account&action=txlist&address=0x"
|
||||||
account "&startblock=0&endblock=99999999&sort=desc&apikey=YourApiKeyToken?q=json")))
|
account "&startblock=0&endblock=99999999&sort=desc&apikey=YourApiKeyToken?q=json")))
|
||||||
|
|
||||||
(defn format-transaction [account {:keys [value timeStamp blockNumber hash from to gas gasPrice gasUsed nonce confirmations input]}]
|
(defn- format-transaction [account {:keys [value timeStamp blockNumber hash from to gas gasPrice gasUsed nonce confirmations input]}]
|
||||||
(let [inbound? (= (str "0x" account) to)]
|
(let [inbound? (= (str "0x" account) to)]
|
||||||
{:value (money/wei->ether value)
|
{:value value
|
||||||
;; timestamp is in seconds, we convert it in ms
|
;; timestamp is in seconds, we convert it in ms
|
||||||
:timestamp (str timeStamp "000")
|
:timestamp (str timeStamp "000")
|
||||||
:symbol "ETH"
|
:symbol "ETH"
|
||||||
|
@ -36,7 +36,7 @@
|
||||||
:confirmations confirmations
|
:confirmations confirmations
|
||||||
:data input}))
|
:data input}))
|
||||||
|
|
||||||
(defn format-transactions-response [response account]
|
(defn- format-transactions-response [response account]
|
||||||
(->> response
|
(->> response
|
||||||
types/json->clj
|
types/json->clj
|
||||||
:result
|
:result
|
||||||
|
|
Loading…
Reference in New Issue