[bug] fix #2128 No feedback on insufficient funds from unsigned

- move current unsigned-transaction to wallet
- move some logic from view to subscriptions and events
This commit is contained in:
Eric Dvorsak 2017-10-13 14:54:50 +02:00 committed by Oskar Thorén
parent f4082951b7
commit 0707af2ad6
14 changed files with 257 additions and 228 deletions

View File

@ -6,12 +6,12 @@
(handlers/register-handler-db (handlers/register-handler-db
:wallet/toggle-flashlight :wallet/toggle-flashlight
(fn [db] (fn [db]
(let [flashlight-state (get-in db [:wallet/send-transaction :camera-flashlight]) (let [flashlight-state (get-in db [:wallet :send-transaction :camera-flashlight])
toggled-state (if (= :on flashlight-state) :off :on)] toggled-state (if (= :on flashlight-state) :off :on)]
(assoc-in db [:wallet/send-transaction :camera-flashlight] toggled-state)))) (assoc-in db [:wallet :send-transaction :camera-flashlight] toggled-state))))
(defn choose-address-and-name [db address name amount] (defn choose-address-and-name [db address name amount]
(update db :wallet/send-transaction assoc :to-address address :to-name name :amount amount)) (update-in db [:wallet :send-transaction] assoc :to-address address :to-name name :amount amount))
(defn- extract-details (defn- extract-details
"First try to parse as EIP67 URI, if not assume this is an address directly. "First try to parse as EIP67 URI, if not assume this is an address directly.
@ -28,13 +28,13 @@
;; isAddress works with or without address with leading '0x' ;; isAddress works with or without address with leading '0x'
valid-address? (.isAddress web3 address)] valid-address? (.isAddress web3 address)]
(cond-> {:db db} (cond-> {:db db}
(= :choose-recipient view-id) (assoc :dispatch [:navigate-back]) (= :choose-recipient view-id) (assoc :dispatch [:navigate-back])
valid-address? (update :db #(choose-address-and-name % address name (:value m))) valid-address? (update :db #(choose-address-and-name % address name (:value m)))
(not valid-address?) (assoc :show-error (i18n/label :t/wallet-invalid-address {:data data})))))) (not valid-address?) (assoc :show-error (i18n/label :t/wallet-invalid-address {:data data}))))))
(handlers/register-handler-fx (handlers/register-handler-fx
:wallet-open-send-transaction :wallet-open-send-transaction
(fn [{db :db} [_ address name]] (fn [{db :db} [_ address name]]
{:db (choose-address-and-name db address name nil) {:db (choose-address-and-name db address name nil)
:dispatch-n [[:navigate-back] :dispatch-n [[:navigate-back]
[:navigate-back]]})) [:navigate-back]]}))

View File

@ -71,18 +71,18 @@
:style (styles/corner-right-bottom min-dimension)}]])) :style (styles/corner-right-bottom min-dimension)}]]))
(defview choose-recipient [] (defview choose-recipient []
(letsubs [camera-dimensions [:camera-dimensions] (letsubs [camera-dimensions [:wallet.send/camera-dimensions]
camera-flashlight [:camera-flashlight] camera-flashlight [:wallet.send/camera-flashlight]
camera-permitted? [:get-in [:wallet/send-transaction :camera-permitted?]]] camera-permitted? [:wallet.send/camera-permitted?]]
[react/view {:style styles/wallet-container} [react/view {:style styles/wallet-container}
[status-bar/status-bar {:type :wallet}] [status-bar/status-bar {:type :wallet}]
[toolbar-view camera-flashlight] [toolbar-view camera-flashlight]
[react/view {:style styles/qr-container [react/view {:style styles/qr-container
:pointerEvents :none :pointerEvents :none
:on-layout #(let [layout (.. % -nativeEvent -layout)] :on-layout #(let [layout (.. % -nativeEvent -layout)]
(re-frame/dispatch [:set-in [:wallet/send-transaction :camera-dimensions] (re-frame/dispatch [:wallet.send/set-camera-dimensions
{:width (.-width layout) {:width (.-width layout)
:height (.-height layout)}]))} :height (.-height layout)}]))}
(when (or platform/android? (when (or platform/android?
camera-permitted?)[camera/camera {:style styles/preview camera-permitted?)[camera/camera {:style styles/preview
:aspect :fill :aspect :fill

View File

@ -21,37 +21,29 @@
[react/text {:style styles/tooltip-text} label]] [react/text {:style styles/tooltip-text} label]]
[vector-icons/icon :icons/tooltip-triangle {:color :white :style styles/tooltip-triangle}]]])) [vector-icons/icon :icons/tooltip-triangle {:color :white :style styles/tooltip-triangle}]]]))
;;TODO (andrey) temporary, should be removed later
(defn amount-input-disabled [amount]
[react/view components.styles/flex
[react/text {:style styles/label} (i18n/label :t/amount)]
[react/view styles/amount-text-input-container
[react/view (merge (styles/amount-container false) styles/container-disabled)
[react/text-input
{:editable false
:default-value amount
:style styles/text-input}]]]])
(defn amount-input [] (defn amount-input []
(let [active? (reagent/atom false)] (let [active? (reagent/atom false)]
(fn [& [{:keys [input-options style error]}]] (fn [& [{:keys [input-options style error disabled?]}]]
(let [{:keys [on-focus on-blur]} input-options] (let [{:keys [on-focus on-blur]} input-options]
[react/view components.styles/flex [react/view components.styles/flex
[react/text {:style styles/label} (i18n/label :t/amount)] [react/text {:style styles/label} (i18n/label :t/amount)]
[react/view styles/amount-text-input-container [react/view styles/amount-text-input-container
[react/view (merge (styles/amount-container @active?) style) [react/view (merge (styles/amount-container @active?) (if disabled? styles/container-disabled style))
[react/text-input [react/text-input
(merge (merge
{:keyboard-type :numeric {:style styles/text-input}
:placeholder "0.000" (if disabled?
:placeholder-text-color "#ffffff66" {:editable false}
:selection-color :white {:keyboard-type :numeric
:style styles/text-input :placeholder "0.000"
:on-focus #(do (reset! active? true) :placeholder-text-color "#ffffff66"
(when on-focus (on-focus))) :selection-color :white
:on-blur #(do (reset! active? false) :style styles/text-input
(when on-blur (on-blur)))} :on-focus #(do (reset! active? true)
(dissoc input-options :on-focus :on-blur))]] (when on-focus (on-focus)))
:on-blur #(do (reset! active? false)
(when on-blur (on-blur)))})
(dissoc input-options :on-focus :on-blur))]]
(when-not (nil? error) (when-not (nil? error)
[tooltip error])]])))) [tooltip error])]]))))
@ -124,4 +116,4 @@
(defn button-text [label] (defn button-text [label]
[react/text {:style styles/button-text [react/text {:style styles/button-text
:font (if platform/android? :medium :default) :font (if platform/android? :medium :default)
:uppercase? (get-in platform/platform-specific [:uppercase?])} label]) :uppercase? (get-in platform/platform-specific [:uppercase?])} label])

View File

@ -13,7 +13,8 @@
(spec/def :wallet/send (spec/keys :req-un [:wallet.send/recipient])) (spec/def :wallet/send (spec/keys :req-un [:wallet.send/recipient]))
(spec/def :wallet/wallet (spec/keys :opt [:wallet/error])) (spec/def :wallet/wallet (spec/keys :opt [:wallet/error]
:opt-un [ :wallet/send-transaction]))
;; Placeholder namespace for wallet specs, which are a WIP depending on data ;; Placeholder namespace for wallet specs, which are a WIP depending on data
;; model we decide on for balances, prices, etc. ;; model we decide on for balances, prices, etc.
@ -36,4 +37,4 @@
(i18n/label :t/validation-amount-invalid-number) (i18n/label :t/validation-amount-invalid-number)
(too-precise-amount? normalized-amount) (too-precise-amount? normalized-amount)
(i18n/label :t/validation-amount-is-too-precise))))) (i18n/label :t/validation-amount-is-too-precise)))))

View File

@ -137,6 +137,13 @@
{:db (assoc-in db [:wallet :current-transaction] hash) {:db (assoc-in db [:wallet :current-transaction] hash)
:dispatch [:navigate-to :wallet-transaction-details]})) :dispatch [:navigate-to :wallet-transaction-details]}))
(handlers/register-handler-fx
:wallet/show-sign-transaction
(fn [{:keys [db]} [_ id from-chat?]]
{:db (assoc-in db [:wallet :send-transaction] {:id id
:from-chat? from-chat?})
:dispatch [:navigate-to-modal :wallet-send-transaction-modal]}))
(handlers/register-handler-fx (handlers/register-handler-fx
:wallet/discard-unsigned-transaction :wallet/discard-unsigned-transaction
(fn [_ [_ transaction-id]] (fn [_ [_ transaction-id]]
@ -148,4 +155,4 @@
{:show-confirmation {:title (i18n/label :t/transactions-delete) {:show-confirmation {:title (i18n/label :t/transactions-delete)
:content (i18n/label :t/transactions-delete-content) :content (i18n/label :t/transactions-delete-content)
:confirm-button-text (i18n/label :t/confirm) :confirm-button-text (i18n/label :t/confirm)
:on-accept #(re-frame/dispatch [:wallet/discard-unsigned-transaction transaction-id])}})) :on-accept #(re-frame/dispatch [:wallet/discard-unsigned-transaction transaction-id])}}))

View File

@ -20,8 +20,4 @@
[db [event]] [db [event]]
(if (= event :navigate-back) (if (= event :navigate-back)
db db
(dissoc db :wallet/send-transaction))) (update db :wallet dissoc :send-transaction)))
(defmethod navigation/preload-data! :wallet-send-transaction-modal
[db [_ _ value]]
(assoc db :wallet/send-transaction value))

View File

@ -8,7 +8,7 @@
(spec/def ::amount-error (spec/nilable string?)) (spec/def ::amount-error (spec/nilable string?))
(spec/def ::password (spec/nilable string?)) (spec/def ::password (spec/nilable string?))
(spec/def ::wrong-password? (spec/nilable boolean?)) (spec/def ::wrong-password? (spec/nilable boolean?))
(spec/def ::transaction-id (spec/nilable string?)) (spec/def ::id (spec/nilable string?))
(spec/def ::waiting-signal? (spec/nilable boolean?)) (spec/def ::waiting-signal? (spec/nilable boolean?))
(spec/def ::signing? (spec/nilable boolean?)) (spec/def ::signing? (spec/nilable boolean?))
(spec/def ::later? (spec/nilable boolean?)) (spec/def ::later? (spec/nilable boolean?))
@ -18,10 +18,10 @@
(spec/def ::camera-flashlight #{:on :off}) (spec/def ::camera-flashlight #{:on :off})
(spec/def ::camera-permitted? boolean?) (spec/def ::camera-permitted? boolean?)
(spec/def ::in-progress? boolean?) (spec/def ::in-progress? boolean?)
(spec/def ::from-chat? boolean?) (spec/def ::from-chat? (spec/nilable boolean?))
(spec/def :wallet/send-transaction (allowed-keys (spec/def :wallet/send-transaction (allowed-keys
:opt-un [::amount ::to-address ::to-name ::amount-error ::password :opt-un [::amount ::to-address ::to-name ::amount-error ::password
::waiting-signal? ::signing? ::transaction-id ::later? ::waiting-signal? ::signing? ::id ::later?
::camera-dimensions ::camera-flashlight ::in-progress? ::camera-dimensions ::camera-flashlight ::in-progress?
::wrong-password? ::camera-permitted? ::from-chat?])) ::wrong-password? ::camera-permitted? ::from-chat?]))

View File

@ -34,13 +34,13 @@
(handlers/register-handler-fx (handlers/register-handler-fx
:wallet/set-and-validate-amount :wallet/set-and-validate-amount
(fn [{{:wallet/keys [send-transaction] :as db} :db} [_ amount]] (fn [{:keys [db]} [_ amount]]
(let [error (wallet.db/get-amount-validation-error amount)] (let [error (wallet.db/get-amount-validation-error amount)]
{:db (-> db {:db (-> db
(assoc-in [:wallet/send-transaction :amount] amount) (assoc-in [:wallet :send-transaction :amount] amount)
(assoc-in [:wallet/send-transaction :amount-error] error))}))) (assoc-in [:wallet :send-transaction :amount-error] error))})))
(def ^:private clear-send-properties {:transaction-id nil (def ^:private clear-send-properties {:id nil
:wrong-password? false :wrong-password? false
:waiting-signal? false :waiting-signal? false
:from-chat? false}) :from-chat? false})
@ -49,11 +49,11 @@
::transaction-completed ::transaction-completed
(fn [{db :db} [_ {:keys [id response]}]] (fn [{db :db} [_ {:keys [id response]}]]
(let [{:keys [hash error]} response (let [{:keys [hash error]} response
db' (assoc-in db [:wallet/send-transaction :in-progress?] false)] db' (assoc-in db [:wallet :send-transaction :in-progress?] false)]
(if-not (and error (string? error) (not (string/blank? error))) (if-not (and error (string? error) (not (string/blank? error)))
{:db (-> db' {:db (-> db'
(update-in [:wallet :transactions-unsigned] dissoc id) (update-in [:wallet :transactions-unsigned] dissoc id)
(update :wallet/send-transaction merge clear-send-properties)) (update-in [:wallet :send-transaction] merge clear-send-properties))
:dispatch [:navigate-to :wallet-transaction-sent]} :dispatch [:navigate-to :wallet-transaction-sent]}
{:db db'})))) {:db db'}))))
@ -66,13 +66,13 @@
::transaction-modal-completed ::transaction-modal-completed
(fn [{db :db} [_ {:keys [id response]}]] (fn [{db :db} [_ {:keys [id response]}]]
(let [{:keys [hash error]} response (let [{:keys [hash error]} response
db' (assoc-in db [:wallet/send-transaction :in-progress?] false) db' (assoc-in db [:wallet :send-transaction :in-progress?] false)
has-error? (and error (string? error) (not (string/blank? error)))] has-error? (and error (string? error) (not (string/blank? error)))]
(if has-error? (if has-error?
{:db db'} {:db db'}
{:db (-> db' {:db (-> db'
(update-in [:wallet :transactions-unsigned] dissoc id) (update-in [:wallet :transactions-unsigned] dissoc id)
(update :wallet/send-transaction merge clear-send-properties)) (update-in [:wallet :send-transaction] merge clear-send-properties))
:dispatch [:navigate-back]})))) :dispatch [:navigate-back]}))))
(defn on-transactions-modal-completed [raw-results] (defn on-transactions-modal-completed [raw-results]
@ -82,56 +82,51 @@
(handlers/register-handler-fx (handlers/register-handler-fx
:wallet.send-transaction/transaction-queued :wallet.send-transaction/transaction-queued
(fn [{{:wallet/keys [send-transaction] :as db} :db} _] (fn [{:keys [db]} _]
(let [{:keys [later? password transaction-id]} send-transaction] (let [{:keys [later? password id]} (get-in db [:wallet :send-transaction])]
(if later? (if later?
{:db (assoc-in db [:wallet/send-transaction :waiting-signal?] false) {:db (assoc-in db [:wallet :send-transaction :waiting-signal?] false)
:dispatch [:navigate-back] :dispatch [:navigate-back]
::show-transaction-moved nil} ::show-transaction-moved nil}
{::accept-transaction {:id transaction-id {::accept-transaction {:id id
:password password :password password
:on-completed on-transactions-completed}})))) :on-completed on-transactions-completed}}))))
(handlers/register-handler-fx (handlers/register-handler-fx
:wallet/sign-transaction :wallet/sign-transaction
(fn [{{:keys [web3] (fn [{{:keys [web3]
: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 id password to-address]} (get-in db [:wallet :send-transaction])]
(if transaction-id (if id
{::accept-transaction {:id transaction-id {::accept-transaction {:id id
:password password :password password
:on-completed on-transactions-completed} :on-completed on-transactions-completed}
:db (assoc-in db [:wallet/send-transaction :in-progress?] true)} :db (assoc-in db [:wallet :send-transaction :in-progress?] true)}
{:db (update db :wallet/send-transaction assoc {:db (update-in db [:wallet :send-transaction] assoc
:waiting-signal? true :waiting-signal? true
:later? later? :later? later?
:in-progress? true) :in-progress? true)
::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
:value (money/to-wei (money/normalize amount))}})))) :value (money/to-wei (money/normalize amount))}}))))
(handlers/register-handler-fx (handlers/register-handler-fx
:wallet/sign-transaction-modal :wallet/sign-transaction-modal
(fn [{{:keys [web3] (fn [{{:keys [web3]
: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 [transaction-id password]} send-transaction] (let [{:keys [id password]} (get-in db [:wallet :send-transaction])]
{:db (assoc-in db [:wallet/send-transaction :in-progress?] true) {:db (assoc-in db [:wallet :send-transaction :in-progress?] true)
::accept-transaction {:id transaction-id ::accept-transaction {:id id
:password password :password password
:on-completed on-transactions-modal-completed}}))) :on-completed on-transactions-modal-completed}})))
(defn discard-transaction (defn discard-transaction
[{{:wallet/keys [send-transaction] :as db} :db}] [{:keys [db]}]
(let [{:keys [transaction-id]} send-transaction] (let [{:keys [id]} (get-in db [:wallet :send-transaction])]
(merge {:db (update db :wallet/send-transaction assoc (merge {:db (update-in db [:wallet :send-transaction] merge clear-send-properties)}
:signing? false (when id
:transaction-id nil {:discard-transaction id}))))
:wrong-password? false)}
(when transaction-id
{:discard-transaction transaction-id}))))
(handlers/register-handler-fx (handlers/register-handler-fx
:wallet/discard-transaction :wallet/discard-transaction
@ -147,7 +142,22 @@
(handlers/register-handler-fx (handlers/register-handler-fx
:wallet/cancel-signing-modal :wallet/cancel-signing-modal
(fn [{{:wallet/keys [send-transaction] :as db} :db} _] (fn [{:keys [db]} _]
(let [{:keys [transaction-id]} send-transaction] {:db (update-in db [:wallet :send-transaction] assoc
{:db (update-in db [:wallet/send-transaction] :signing? false
assoc :signing? false :wrong-password? false)}))) :wrong-password? false)}))
(handlers/register-handler-fx
:wallet.send/set-camera-dimensions
(fn [{:keys [db]} [_ camera-dimensions]]
{:db (assoc-in db [:wallet :send-transaction :camera-dimensions] camera-dimensions)}))
(handlers/register-handler-fx
:wallet.send/set-password
(fn [{:keys [db]} [_ password]]
{:db (assoc-in db [:wallet :send-transaction :password] password)}))
(handlers/register-handler-fx
:wallet.send/set-signing?
(fn [{:keys [db]} [_ signing?]]
{:db (assoc-in db [:wallet :send-transaction :signing?] signing?)}))

View File

@ -1,27 +1,76 @@
(ns status-im.ui.screens.wallet.send.subs (ns status-im.ui.screens.wallet.send.subs
(:require [re-frame.core :as re-frame])) (:require [re-frame.core :as re-frame]
[status-im.i18n :as i18n]
[status-im.utils.money :as money]
[status-im.utils.hex :as utils.hex]))
(re-frame/reg-sub :camera-dimensions (re-frame/reg-sub ::send-transaction
(fn [db] :<- [:wallet]
(get-in db [:wallet/send-transaction :camera-dimensions]))) (fn [wallet]
(:send-transaction wallet)))
(re-frame/reg-sub :camera-flashlight (re-frame/reg-sub :wallet.send/camera-dimensions
(fn [db] :<- [::send-transaction]
(get-in db [:wallet/send-transaction :camera-flashlight]))) (fn [send-transaction]
(:camera-dimensions send-transaction)))
(re-frame/reg-sub (re-frame/reg-sub :wallet.send/camera-flashlight
:wallet.send/sign-enabled? :<- [::send-transaction]
:<- [:get-in [:wallet/send-transaction :amount]] (fn [send-transaction]
:<- [:get-in [:wallet/send-transaction :to-address]] (:camera-flashlight send-transaction)))
:<- [:get-in [:wallet/send-transaction :amount-error]]
(fn [[amount to-address amount-error]]
(and
(nil? amount-error)
(not (nil? to-address)) (not= to-address "")
(not (nil? amount)) (not= amount ""))))
(re-frame/reg-sub (re-frame/reg-sub :wallet.send/camera-permitted?
:wallet.send/sign-password-enabled? :<- [::send-transaction]
:<- [:get-in [:wallet/send-transaction :password]] (fn [send-transaction]
(fn [password] (:camera-permitted? send-transaction)))
(re-frame/reg-sub :wallet.send/wrong-password?
:<- [::send-transaction]
(fn [send-transaction]
(:wrong-password? send-transaction)))
(re-frame/reg-sub :wallet.send/sign-password-enabled?
:<- [::send-transaction]
(fn [{:keys [password]}]
(and (not (nil? password)) (not= password "")))) (and (not (nil? password)) (not= password ""))))
(re-frame/reg-sub ::unsigned-transactions
:<- [:wallet]
(fn [wallet]
(:transactions-unsigned wallet)))
(re-frame/reg-sub ::unsigned-transaction
:<- [::send-transaction]
:<- [::unsigned-transactions]
(fn [[send-transaction unsigned-transactions]]
(when-let [unsigned-transaction (get unsigned-transactions
(:id send-transaction))]
(merge send-transaction
unsigned-transaction))))
(defn sign-enabled? [amount-error to-address amount]
(and
(nil? amount-error)
(not (nil? to-address)) (not= to-address "")
(not (nil? amount)) (not= amount "")))
(re-frame/reg-sub :wallet.send/transaction
:<- [::send-transaction]
:<- [:balance]
(fn [[{:keys [amount to] :as transaction} balance]]
(assoc transaction :sufficient-funds? (or (nil? amount)
(money/sufficient-funds? amount balance)))))
(re-frame/reg-sub :wallet.send/unsigned-transaction
:<- [::unsigned-transaction]
:<- [:contacts/by-address]
:<- [:balance]
(fn [[{:keys [value to] :as transaction} contacts balance]]
(when transaction
(let [contact (contacts (utils.hex/normalize-hex to))
amount (str (.toFixed (money/wei->ether value)))
sufficient-funds? (money/sufficient-funds? amount balance)]
(cond-> (assoc transaction
:amount amount
:sufficient-funds? sufficient-funds?)
contact (assoc :to-name (:name contact)))))))

View File

@ -1,24 +1,23 @@
(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 [re-frame.core :as re-frame] (:require [re-frame.core :as re-frame]
[status-im.components.animation :as animation] [status-im.components.animation :as animation]
[status-im.components.camera :as camera]
[status-im.components.common.common :as common]
[status-im.components.icons.vector-icons :as vector-icons] [status-im.components.icons.vector-icons :as vector-icons]
[status-im.components.react :as react] [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.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.common.common :as common]
[status-im.utils.utils :as utils]
[status-im.i18n :as i18n] [status-im.i18n :as i18n]
[status-im.ui.screens.wallet.components.views :as components]
[status-im.ui.screens.wallet.send.animations :as send.animations]
[status-im.ui.screens.wallet.send.styles :as send.styles]
[status-im.ui.screens.wallet.styles :as wallet.styles]
[status-im.utils.money :as money] [status-im.utils.money :as money]
[status-im.utils.platform :as platform] [status-im.utils.platform :as platform]
[status-im.ui.screens.wallet.request.styles :as request.styles] [status-im.utils.utils :as utils])
[status-im.ui.screens.wallet.components.views :as components] (:require-macros [status-im.utils.views :refer [defview letsubs]]))
[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.styles :as send.styles]))
(defn toolbar-view [signing?] (defn toolbar-view [signing?]
[toolbar/toolbar2 {:style wallet.styles/toolbar} [toolbar/toolbar2 {:style wallet.styles/toolbar}
@ -29,30 +28,30 @@
(defn sign-later [] (defn sign-later []
(utils/show-question (utils/show-question
(i18n/label :t/sign-later-title) (i18n/label :t/sign-later-title)
(i18n/label :t/sign-later-text) (i18n/label :t/sign-later-text)
#(re-frame/dispatch [:wallet/sign-transaction true]))) #(re-frame/dispatch [:wallet/sign-transaction true])))
(defview sign-panel [] (defview sign-panel []
(letsubs [account [:get-current-account] (letsubs [account [:get-current-account]
wrong-password? [:get-in [:wallet/send-transaction :wrong-password?]] wrong-password? [:wallet.send/wrong-password?]
signing-phrase (:signing-phrase @account) signing-phrase (:signing-phrase @account)
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 (send.styles/animated-sign-panel bottom-value)} [react/animated-view {:style (send.styles/animated-sign-panel bottom-value)}
[react/animated-view {:style (send.styles/sign-panel opacity-value)} [react/animated-view {:style (send.styles/sign-panel opacity-value)}
[react/view send.styles/signing-phrase-container [react/view send.styles/signing-phrase-container
[react/text {:style send.styles/signing-phrase} signing-phrase]] [react/text {:style send.styles/signing-phrase} signing-phrase]]
[react/text {:style send.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 send.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 #(re-frame/dispatch [:set-in [:wallet/send-transaction :password] %]) :on-change-text #(re-frame/dispatch [:wallet.send/set-password %])
:style send.styles/password}]]] :style send.styles/password}]]]
(when wrong-password? (when wrong-password?
[components/tooltip (i18n/label :t/wrong-password)])])) [components/tooltip (i18n/label :t/wrong-password)])]))
@ -73,9 +72,9 @@
(defn sign-enabled? [amount-error to-address amount] (defn sign-enabled? [amount-error to-address amount]
(and (and
(nil? amount-error) (nil? amount-error)
(not (nil? to-address)) (not= to-address "") (not (nil? to-address)) (not= to-address "")
(not (nil? amount)) (not= amount ""))) (not (nil? amount)) (not= amount "")))
;; "Sign Later" and "Sign Transaction >" buttons ;; "Sign Later" and "Sign Transaction >" buttons
(defn- sign-buttons [amount-error to-address amount sufficient-funds? sign-later-handler] (defn- sign-buttons [amount-error to-address amount sufficient-funds? sign-later-handler]
@ -88,31 +87,22 @@
[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 {:style wallet.styles/button [react/touchable-highlight {:style wallet.styles/button
:on-press (when immediate-sign-enabled? #(re-frame/dispatch [:set-in [:wallet/send-transaction :signing?] true]))} :on-press (when immediate-sign-enabled? #(re-frame/dispatch [:wallet.send/set-signing? true]))}
[react/view (wallet.styles/button-container immediate-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)]
[vector-icons/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-in-eth balance]
(.greaterThanOrEqualTo balance (money/bignumber (money/to-wei amount-in-eth))))
(defn request-camera-permissions [] (defn request-camera-permissions []
(when platform/android? (when platform/android?
(re-frame/dispatch [:request-permissions [:camera]])) (re-frame/dispatch [:request-permissions [:camera]]))
(camera/request-access (camera/request-access
(fn [permitted?] (fn [permitted?]
(re-frame/dispatch [:set-in [:wallet/send-transaction :camera-permitted?] permitted?]) (re-frame/dispatch [:set-in [:wallet :send-transaction :camera-permitted?] permitted?])
(re-frame/dispatch [:navigate-to :choose-recipient])))) (re-frame/dispatch [:navigate-to :choose-recipient]))))
(defview send-transaction [] (defview send-transaction []
(letsubs [balance [:balance] (letsubs [transaction [:wallet.send/transaction]]
amount [:get-in [:wallet/send-transaction :amount]] (let [{:keys [amount amount-error signing? to-address to-name in-progress? sufficient-funds?]} transaction]
amount-error [:get-in [:wallet/send-transaction :amount-error]]
signing? [:get-in [:wallet/send-transaction :signing?]]
to-address [:get-in [:wallet/send-transaction :to-address]]
to-name [:get-in [:wallet/send-transaction :to-name]]
in-progress? [:get-in [:wallet/send-transaction :in-progress?]]]
(let [sufficient-funds? (or (nil? amount) (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}]
@ -154,37 +144,34 @@
[toolbar/content-title {:color :white} (i18n/label :t/send-transaction)]]) [toolbar/content-title {:color :white} (i18n/label :t/send-transaction)]])
(defview send-transaction-modal [] (defview send-transaction-modal []
(letsubs [amount [:get-in [:wallet/send-transaction :amount]] (letsubs [transaction [:wallet.send/unsigned-transaction]]
amount-error [:get-in [:wallet/send-transaction :amount-error]] (let [{:keys [amount amount-error signing? to to-name sufficient-funds? in-progress? from-chat?]} transaction]
signing? [:get-in [:wallet/send-transaction :signing?]] [react/keyboard-avoiding-view wallet.styles/wallet-modal-container
to-address [:get-in [:wallet/send-transaction :to-address]]
to-name [:get-in [:wallet/send-transaction :to-name]]
recipient [:contact-by-address @to-name]
in-progress? [:get-in [:wallet/send-transaction :in-progress?]]
from-chat? [:get-in [:wallet/send-transaction :from-chat?]]]
[react/keyboard-avoiding-view wallet.styles/wallet-modal-container
[react/view components.styles/flex
[status-bar/status-bar {:type :modal-wallet}]
[toolbar-modal from-chat?]
[common/network-info {:text-color :white}]
[react/scroll-view {:keyboardShouldPersistTaps :always}
[react/view components.styles/flex [react/view components.styles/flex
[react/view wallet.styles/choose-participant-container [status-bar/status-bar {:type :modal-wallet}]
[components/choose-recipient-disabled {:address to-address [toolbar-modal from-chat?]
:name (:name recipient)}]] [common/network-info {:text-color :white}]
[react/view wallet.styles/choose-wallet-container [react/scroll-view {:keyboardShouldPersistTaps :always}
[components/choose-wallet]] [react/view components.styles/flex
[react/view wallet.styles/amount-container [react/view wallet.styles/choose-participant-container
[components/amount-input-disabled amount] [components/choose-recipient-disabled {:address to
[react/view wallet.styles/choose-currency-container :name to-name}]]
[components/choose-currency wallet.styles/choose-currency]]]]] [react/view wallet.styles/choose-wallet-container
[components/separator] [components/choose-wallet]]
(if signing? [react/view wallet.styles/amount-container
[signing-buttons [components/amount-input
#(re-frame/dispatch [:wallet/cancel-signing-modal]) {:error (when-not sufficient-funds? (i18n/label :t/wallet-insufficient-funds))
#(re-frame/dispatch [:wallet/sign-transaction-modal]) :disabled? true
in-progress?] :input-options {:default-value amount}}]
[sign-buttons amount-error to-address amount true #(re-frame/dispatch [:navigate-back])]) [react/view wallet.styles/choose-currency-container
(when signing? [components/choose-currency wallet.styles/choose-currency]]]]]
[sign-panel])] [components/separator]
(when in-progress? [react/view send.styles/processing-view])])) (if signing?
[signing-buttons
#(re-frame/dispatch [:wallet/cancel-signing-modal])
#(re-frame/dispatch [:wallet/sign-transaction-modal])
in-progress?]
[sign-buttons amount-error to amount sufficient-funds? #(re-frame/dispatch [:navigate-back])])
(when signing?
[sign-panel])
(when in-progress? [react/view send.styles/processing-view])]])))

View File

@ -21,39 +21,35 @@
;;Handlers ;;Handlers
;TRANSACTION QUEUED signal from status-go ;;TRANSACTION QUEUED signal from status-go
(handlers/register-handler-fx (handlers/register-handler-fx
:transaction-queued :transaction-queued
[(re-frame/inject-cofx :now)] [(re-frame/inject-cofx :now)]
(fn [{{:wallet/keys [send-transaction] :as db} :db now :now} [_ {:keys [id message_id args] :as transaction}]] (fn [{:keys [db now]} [_ {:keys [id message_id args] :as transaction}]]
(if (transaction-valid? transaction) (if (transaction-valid? transaction)
(let [{:keys [from to value data gas gasPrice]} args] (let [{:keys [from to value data gas gasPrice]} args
(let [;;TODO (andrey) revisit this map later (this map from old transactions, idk if we need all these fields) ;;TODO (andrey) revisit this map later (this map from old transactions, idk if we need all these fields)
transaction {:id id transaction {:id id
:from from :from from
:to to :to to
:value (money/bignumber value) :value (money/bignumber value)
:data data :data data
:gas (money/to-decimal gas) :gas (money/to-decimal gas)
:gas-price (money/to-decimal gasPrice) :gas-price (money/to-decimal gasPrice)
:timestamp now :timestamp now
:message-id message_id}] :message-id message_id}]
(merge (merge
{:db (-> db {:db (-> db
(assoc-in [:wallet :transactions-unsigned id] transaction) (assoc-in [:wallet :transactions-unsigned id] transaction)
(assoc-in [:wallet/send-transaction :transaction-id] id))} (assoc-in [:wallet :send-transaction :id] id))}
(if (:waiting-signal? send-transaction) (if (get-in db [:wallet :send-transaction :waiting-signal?])
;;sending from wallet ;;sending from wallet
{:dispatch [:wallet.send-transaction/transaction-queued id]} {:dispatch [:wallet.send-transaction/transaction-queued id]}
;;sending from chat ;;sending from chat
{:dispatch [:navigate-to-modal :wallet-send-transaction-modal {:amount (str (money/wei->ether value)) {:dispatch [:navigate-to-modal :wallet-send-transaction-modal id :from-chat]})))
:transaction-id id
:to-address to
:to-name to
:from-chat? true}]}))))
{:discard-transaction id}))) {:discard-transaction id})))
;TRANSACTION FAILED signal from status-go ;;TRANSACTION FAILED signal from status-go
(handlers/register-handler-fx (handlers/register-handler-fx
:transaction-failed :transaction-failed
(fn [{{:accounts/keys [accounts current-account-id] :as db} :db} [_ {:keys [id args message_id error_code error_message] :as event}]] (fn [{{:accounts/keys [accounts current-account-id] :as db} :db} [_ {:keys [id args message_id error_code error_message] :as event}]]
@ -63,7 +59,7 @@
;;WRONG PASSWORD ;;WRONG PASSWORD
constants/send-transaction-password-error-code constants/send-transaction-password-error-code
{:db (assoc-in db [:wallet/send-transaction :wrong-password?] true)} {:db (assoc-in db [:wallet :send-transaction :wrong-password?] true)}
;;TODO (andrey) something weird here below, revisit ;;TODO (andrey) something weird here below, revisit
;;DISCARDED ;;DISCARDED
@ -73,6 +69,6 @@
;;NO ERROR, TIMEOUT or DEFAULT ERROR ;;NO ERROR, TIMEOUT or DEFAULT ERROR
(merge (merge
{:db (update-in db [:wallet :transactions-unsigned] dissoc id)} {:db (update-in db [:wallet :transactions-unsigned] dissoc id)}
(when (and message_id (= current-account-address transaction-initiator-address)) (when (and message_id (= current-account-address transaction-initiator-address))
{:dispatch [:set-chat-ui-props {:validation-messages error_message}]})))))) {:dispatch [:set-chat-ui-props {:validation-messages error_message}]}))))))

View File

@ -160,10 +160,3 @@
(if (>= confirmations max-confirmations) (if (>= confirmations max-confirmations)
100 100
(* 100 (/ confirmations max-confirmations)))))) (* 100 (/ confirmations max-confirmations))))))
(reg-sub :contact-by-address
:<- [:contacts/by-address]
(fn [contacts [_ address]]
(let [address' (when address
(utils.hex/normalize-hex address))]
(contacts address'))))

View File

@ -50,12 +50,7 @@
(defn action-buttons [{:keys [id to value] :as transaction}] (defn action-buttons [{:keys [id to value] :as transaction}]
[react/view {:style transactions.styles/action-buttons} [react/view {:style transactions.styles/action-buttons}
[button/primary-button {:style {:margin-right 12} [button/primary-button {:style {:margin-right 12}
:on-press #(re-frame/dispatch [:navigate-to-modal :on-press #(re-frame/dispatch [:wallet/show-sign-transaction id])}
:wallet-send-transaction-modal
{:amount (str (money/wei->ether value))
:transaction-id id
:to-address to
:to-name to}])}
(i18n/label :t/transactions-sign)] (i18n/label :t/transactions-sign)]
[button/secondary-button {:on-press #(on-delete-transaction transaction)} [button/secondary-button {:on-press #(on-delete-transaction transaction)}
(i18n/label :t/delete)]]) (i18n/label :t/delete)]])

View File

@ -85,3 +85,6 @@
(defn with-precision [n decimals] (defn with-precision [n decimals]
(.round (bignumber n) decimals)) (.round (bignumber n) decimals))
(defn sufficient-funds? [amount-in-eth balance]
(.greaterThanOrEqualTo balance (bignumber (to-wei amount-in-eth))))