send command and remove old wallet

This commit is contained in:
Andrey Shovkoplyas 2017-10-04 17:50:17 +03:00 committed by Roman Volosovskyi
parent 91bb69c6f7
commit 54d68081b4
29 changed files with 314 additions and 871 deletions

View File

@ -101,26 +101,6 @@
status)
:on-press #(rf/dispatch [:my-profile.drawer/edit-status])}])])))
(defview transaction-list-item [{:keys [to value timestamp] :as transaction}]
[recipient [:contact-by-address to]]
(let [eth-value (str (money/wei->ether value))
value (i18n/label-number eth-value)
recipient-name (or (:name recipient) to)]
[touchable-highlight {:on-press #(rf/dispatch [:navigate-to-modal :transaction-details transaction])}
[view {:style st/transaction}
[vi/icon :icons/arrow-right {:container-style st/transaction-icon}]
[view {:style st/transaction-info}
[view {:style st/transaction-value-container}
[text {:style st/transaction-value :font :medium} value]
[text {:style st/transaction-unit} "ETH"]]
[view {:style st/transaction-details-container}
[text {:style st/transaction-to} (i18n/label :t/to)]
[text {:style st/transaction-recipient :number-of-lines 1} recipient-name]
[text {:style st/transaction-time} (time/format-date "dd MMM HH:mm" (time/to-date timestamp))]]]
[view {:style st/transaction-picture}
(when recipient
[ci/chat-icon (:photo-path recipient) {:size 40}])]]]))
(defn render-separator-fn [transactions-count]
(fn [_ row-id _]
(when (< row-id (dec transactions-count))
@ -128,26 +108,6 @@
^{:key row-id}
[common/separator {} st/transactions-list-separator]))))
(defview unsigned-transactions []
[all-transactions [:transactions]]
(let [transactions (take 2 (sort-by :timestamp > all-transactions))]
(if (empty? transactions)
[view {:style st/empty-transactions-title-container}
[text {:style st/transactions-title} (i18n/label :t/no-unsigned-transactions)]]
[view
[view {:style st/transactions-title-container}
[text {:style st/transactions-title} (i18n/label :t/unsigned-transactions)]]
[list-view {:dataSource (lw/to-datasource transactions)
:renderSeparator (render-separator-fn (count transactions))
:renderRow (fn [row _ _] (list-item [transaction-list-item row]))}]
[touchable-opacity {:style st/view-all-transactions-button
:on-press #(rf/dispatch [:navigate-to-modal :unsigned-transactions])}
[text {:style st/view-all-transactions-text
:font (if platform/android? :medium :default)
:uppercase? platform/android?}
(i18n/label :t/view-all)]]])))
(defview current-network []
(letsubs [network [:get-current-account-network]]
[view {:style st/network-label-container}
@ -182,7 +142,6 @@
[options-btn]]
[current-network]]
[view
[unsigned-transactions]
[switch-account]]]]))
(defn drawer-view [items]

View File

@ -70,3 +70,9 @@
:DataDir "/ethereum/mainnet_rpc"
:UpstreamConfig {:Enabled true
:URL "https://mainnet.infura.io/z6GCTmjdP3FETEJmMBI4 "}}}}))
(def ^:const send-transaction-no-error-code "0")
(def ^:const send-transaction-default-error-code "1")
(def ^:const send-transaction-password-error-code "2")
(def ^:const send-transaction-timeout-error-code "3")
(def ^:const send-transaction-discarded-error-code "4")

View File

@ -1,233 +0,0 @@
(ns status-im.transactions.handlers
(:require [re-frame.core :refer [after dispatch debug enrich]]
[status-im.utils.handlers :refer [register-handler]]
[status-im.ui.screens.navigation :as nav]
[status-im.utils.datetime :as time]
[status-im.utils.handlers :as u]
[status-im.utils.types :as t]
[status-im.utils.hex :refer [valid-hex? normalize-hex]]
[status-im.native-module.core :as status]
[clojure.string :as s]
[taoensso.timbre :as log]))
;; flow:
;; :accept-transactions
;; ↓
;; :transaction-completed
;; ↓
;; ::remove-transaction && [:set :wrong-password? false] <- on error
;; ::remove-transaction <- when transaction is
;; not from the jail
;; ::add-transactions-hash
;; && ::check-completed-transaction!
;; && :navigation-replace <- on success
(defmethod nav/preload-data! :unsigned-transactions
[{:keys [transactions-queue] :as db} _]
(-> db
(assoc :transactions transactions-queue
:wrong-password-counter 0
:wrong-password? false)
(assoc-in [:confirm-transactions :password] "")))
(defmethod nav/preload-data! :transaction-details
[db [_ _ transaction]]
(-> db
(assoc :selected-transaction transaction
:wrong-password-counter 0
:wrong-password? false)
(assoc-in [:confirm-transactions :password] "")))
(defn on-transactions-completed [raw-results]
(let [results (:results (t/json->clj raw-results))]
(doseq [result results]
(dispatch [:transaction-completed {:id (name (key result)) :response (second result)}]))))
(register-handler :accept-transactions
(u/side-effect!
(fn [{:keys [transactions]} [_ password]]
(dispatch [:set :wrong-password? false])
(status/complete-transactions (keys transactions) password on-transactions-completed))))
(register-handler :accept-transaction
(u/side-effect!
(fn [_ [_ password id]]
(dispatch [:set :wrong-password? false])
(status/complete-transactions (list id) password on-transactions-completed))))
(register-handler :deny-transactions
(u/side-effect!
(fn [{:keys [transactions]}]
(let [transactions' (vals transactions)
messages-ids (map :message-id transactions')
ids (map :id transactions')]
(dispatch [::remove-pending-messages messages-ids])
(dispatch [::remove-transactions ids])
(doseq [id ids]
(dispatch [::discard-transaction id]))))))
(register-handler :deny-transaction
(u/side-effect!
(fn [{:keys [transactions]} [_ id]]
(let [{:keys [message-id] :as transaction} (get transactions id)]
(when transaction
(dispatch [::remove-pending-message message-id])
(dispatch [::remove-transaction id])
(dispatch [::discard-transaction id]))))))
(register-handler ::discard-transaction
(u/side-effect!
(fn [_ [_ id]]
(status/discard-transaction id))))
(register-handler ::remove-transactions
(fn [db [_ hashes]]
(-> db
(dissoc :transactions)
(update :transactions-queue #(apply dissoc % hashes)))))
(register-handler ::remove-transaction
(fn [db [_ hash]]
(-> db
(update :transactions dissoc hash)
(update :transactions-queue dissoc hash))))
(register-handler :wait-for-transaction
(after (fn [_ [_ message-id]]
(dispatch [::check-completed-transaction!
{:message-id message-id}])))
(fn [db [_ message-id params]]
(assoc-in db [:transaction-subscribers message-id] params)))
(defn remove-pending-message
[{:keys [command->chat] :as db} message-id]
(let [chat-id (get command->chat message-id)]
(if chat-id
(update db :transaction-subscribers dissoc message-id)
db)))
(register-handler ::remove-pending-messages
(fn [db [_ ids]]
(log/debug :message-ids ids)
(reduce remove-pending-message db ids)))
(register-handler ::remove-pending-message
(fn [db [_ message-id]]
(remove-pending-message db message-id)))
(defn transaction-valid? [{{:keys [to data]} :args}]
(or (and to (valid-hex? to)) (and data (not= data "0x"))))
(register-handler :transaction-queued
(u/side-effect!
(fn [_ [_ {:keys [id] :as transaction}]]
(if (transaction-valid? transaction)
(dispatch [::transaction-queued transaction])
(status/discard-transaction id)))))
(register-handler ::transaction-queued
(fn [{:wallet/keys [send-transaction] :as db} [_ {:keys [id message_id args] :as transaction}]]
(let [{:keys [from to value data gas gasPrice]} args]
(if (transaction-valid? transaction)
(let [transaction {:id id
:from from
:to to
:value (.toDecimal js/Web3.prototype value)
:data data
:gas (.toDecimal js/Web3.prototype gas)
:gas-price (.toDecimal js/Web3.prototype gasPrice)
:timestamp (time/now-ms)
:message-id message_id}]
(if (:waiting-signal? send-transaction)
(dispatch [:wallet/transaction-queued id])
(dispatch [:navigate-to-modal :unsigned-transactions]))
(assoc-in db [:transactions-queue id] transaction))
db))))
(register-handler :transaction-completed
(u/side-effect!
(fn [{:keys [transactions modal]} [_ {:keys [id response]}]]
(let [{:keys [hash error]} response
{:keys [message-id]} (get transactions id)]
(log/debug :parsed-response response)
(when-not (and error (string? error) (not (s/blank? error)))
(if (and message-id (not (s/blank? message-id)))
(do (dispatch [::add-transactions-hash {:id id
:hash hash
:message-id message-id}])
(dispatch [::check-completed-transaction! {:message-id message-id}]))
(dispatch [::remove-transaction id]))
(when (#{:unsigned-transactions :transaction-details} modal)
(dispatch [:navigate-to-modal :confirmation-success])))))))
(register-handler ::add-transactions-hash
(fn [db [_ {:keys [id hash message-id]}]]
(-> db
(assoc-in [:transactions id :hash] hash)
(assoc-in [:message-id->transaction-id message-id] id))))
(register-handler ::send-pending-message
(u/side-effect!
(fn [{:keys [transaction-subscribers]} [_ message-id hash]]
(when-let [{:keys [chat-id] :as params} (transaction-subscribers message-id)]
(let [params' (assoc-in params [:handler-data :transaction-hash] hash)]
(dispatch [:prepare-command! chat-id params']))
(dispatch [::remove-transaction-subscriber message-id])))))
(register-handler ::remove-transaction-subscriber
(fn [db [_ old-hash]]
(update db :transaction-subscribers dissoc old-hash)))
(register-handler ::check-completed-transaction!
(u/side-effect!
(fn [{:keys [message-id->transaction-id transactions transaction-subscribers]}
[_ {:keys [message-id]}]]
(let [id (get message-id->transaction-id message-id)
{:keys [hash]} (get transactions id)
pending-message (get transaction-subscribers message-id)]
(when (and pending-message id hash)
(dispatch [::send-pending-message message-id hash]))
;; todo revisit this
(dispatch [::remove-transaction id])))))
(def wrong-password-code "2")
(def discard-code "4")
(register-handler :transaction-failed
(u/side-effect!
(fn [{:accounts/keys [accounts current-account-id]} [_ {:keys [id args message_id error_code error_message] :as event}]]
(let [current-account-address (:address (get accounts current-account-id))
transaction-initiator-address (normalize-hex (:from args))]
(cond
(= error_code wrong-password-code)
(dispatch [:set-wrong-password!])
(not= discard-code error_code)
(do (when message_id
(dispatch [::remove-pending-message message_id]))
(dispatch [:clear-selected-transaction])
(dispatch [::remove-transaction id])
(when (= current-account-address transaction-initiator-address)
(dispatch [:set-chat-ui-props {:validation-messages error_message}])))
:else
(dispatch [:set-chat-ui-props {:validation-messages nil}]))))))
(register-handler :clear-selected-transaction
(fn [db _]
(dissoc db :selected-transaction)))
(def attempts-limit 3)
(register-handler :set-wrong-password!
(after (fn [{:keys [wrong-password-counter]}]
(when (>= wrong-password-counter attempts-limit)
(dispatch [:set :wrong-password? false])
(dispatch [:set :wrong-password-counter 0])
(dispatch [:set-in [:confirm-transactions :password] ""]))))
(fn [db]
(-> db
(assoc :wrong-password? true)
(update :wrong-password-counter (fnil inc 0)))))

View File

@ -1,25 +0,0 @@
(ns status-im.transactions.screens.confirmation-success
(:require-macros [status-im.utils.views :refer [defview]])
(:require [re-frame.core :as rf]
[status-im.components.react :as rn]
[status-im.components.sticky-button :as sticky-button]
[status-im.components.status-bar :as status-bar]
[status-im.transactions.views.list-item :as transactions-list-item]
[status-im.transactions.styles.screens :as st]
[status-im.i18n :as i18n]))
(defview confirmation-success []
[quantity [:get :confirmed-transactions-count]]
[rn/view {:style st/success-screen}
[status-bar/status-bar {:type :transaction}]
[rn/view {:style st/success-screen-content-container}
[rn/view {:style st/success-icon-container}
[rn/image {:source {:uri :icon_ok_white}
:style st/success-icon}]]
[rn/view
[rn/text {:style st/success-text}
(i18n/label-pluralize quantity :t/transactions-confirmed)]]]
[sticky-button/sticky-button
(i18n/label :t/got-it)
#(do (rf/dispatch [:navigate-back])
(rf/dispatch [:set :confirmed-transactions-count 0]))]])

View File

@ -1,80 +0,0 @@
(ns status-im.transactions.screens.transaction-details
(:require-macros [status-im.utils.views :refer [defview]])
(:require [re-frame.core :as rf]
[status-im.components.react :as rn]
[status-im.components.common.common :as common]
[status-im.components.sticky-button :as sticky-button]
[status-im.components.status-bar :as status-bar]
[status-im.components.sync-state.offline :as offline-view]
[status-im.components.toolbar-new.actions :as act]
[status-im.components.toolbar-new.view :as toolbar]
[status-im.i18n :as i18n]
[status-im.transactions.styles.screens :as st]
[status-im.transactions.views.list-item :as transactions-list-item]
[status-im.transactions.views.password-form :as password-form]
[status-im.utils.platform :as platform]
[status-im.utils.money :as money]))
(defn toolbar-view []
[toolbar/toolbar2
{:background-color st/transactions-toolbar-background
:border-style st/toolbar-border}
[toolbar/nav-button (act/back-white #(rf/dispatch [:navigate-to-modal :unsigned-transactions]))]
[rn/view {:style st/toolbar-title-container}
[rn/text {:style st/toolbar-title-text
:font :toolbar-title}
(i18n/label :t/transaction)]]])
(defn detail-item [title content name?]
[rn/view {:style st/details-item}
[rn/text {:style st/details-item-title} title]
[rn/text {:style (st/details-item-content name?)
:number-of-lines 1}
content]])
(defn detail-data [content]
[rn/view {:style st/details-data}
[rn/text {:style st/details-data-title} (i18n/label :t/data)]
[rn/text {:style st/details-data-content} content]])
(defview details [{:keys [to data gas gas-price] :as transaction}]
[current-account [:get-current-account]
recipient [:contact-by-address to]]
(let [recipient-name (or (:name recipient) to (i18n/label :t/contract-creation))
gas-price' (money/wei->ether gas-price)
fee-value (money/fee-value gas gas-price')
estimated-fee (str fee-value " ETH")]
[rn/view st/details-container
[detail-item (i18n/label :t/to) recipient-name true]
[detail-item (i18n/label :t/from) (:name current-account) true]
[detail-item (i18n/label :t/estimated-fee) estimated-fee]
[detail-data data]]))
(defview transaction-details []
[{:keys [id] :as transaction} [:get :selected-transaction]
{:keys [password]} [:get :confirm-transactions]
confirmed? [:get-in [:transaction-details-ui-props :confirmed?]]
sync-state [:sync-state]
network-status [:get :network-status]]
{:component-did-update #(when-not transaction (rf/dispatch [:navigate-to-modal :unsigned-transactions]))
:component-will-unmount #(rf/dispatch [:set-in [:transaction-details-ui-props :confirmed?] false])}
(let [offline? (or (= network-status :offline) (= sync-state :offline))]
[rn/keyboard-avoiding-view {:style st/transactions-screen}
[status-bar/status-bar {:type :transaction}]
[toolbar-view]
[rn/scroll-view st/details-screen-content-container
[transactions-list-item/view transaction #(rf/dispatch [:navigate-to-modal :unsigned-transactions])]
[common/separator st/details-separator st/details-separator-wrapper]
[details transaction]]
(when (and confirmed? (not offline?))
[password-form/view 1])
(when-not offline?
(let [confirm-text (if confirmed?
(i18n/label :t/confirm)
(i18n/label-pluralize 1 :t/confirm-transactions))
confirm-fn (if confirmed?
#(do (rf/dispatch [:accept-transaction password id])
(rf/dispatch [:set :confirmed-transactions-count 1]))
#(rf/dispatch [:set-in [:transaction-details-ui-props :confirmed?] true]))]
[sticky-button/sticky-button confirm-text confirm-fn true]))
[offline-view/offline-view {:top (if platform/ios? 21 0)}]]))

View File

@ -1,72 +0,0 @@
(ns status-im.transactions.screens.unsigned-transactions
(:require-macros [status-im.utils.views :refer [defview]])
(:require [re-frame.core :as rf]
[status-im.components.common.common :as common]
[status-im.components.react :as rn]
[status-im.components.sticky-button :as sticky-button]
[status-im.components.status-bar :as status-bar]
[status-im.components.sync-state.offline :as offline-view]
[status-im.components.toolbar-new.actions :as act]
[status-im.components.toolbar-new.view :as toolbar]
[status-im.transactions.views.list-item :as transactions-list-item]
[status-im.transactions.views.password-form :as password-form]
[status-im.transactions.styles.screens :as st]
[status-im.utils.listview :as lw]
[status-im.utils.platform :as platform]
[status-im.i18n :as i18n]))
(defn toolbar-view [transactions]
[toolbar/toolbar
{:background-color st/transactions-toolbar-background
:nav-action (act/close-white #(rf/dispatch [:navigate-back]))
:border-style st/toolbar-border
:custom-content [rn/view {:style st/toolbar-title-container}
[rn/text {:style st/toolbar-title-text
:font :toolbar-title}
(i18n/label :t/unsigned-transactions)]
[rn/text {:style st/toolbar-title-count
:font :toolbar-title}
(count transactions)]]}])
(defn render-separator-fn [transactions-count]
(fn [_ row-id _]
(when (< row-id (dec transactions-count))
(rn/list-item
^{:key row-id}
[common/separator {} st/transactions-list-separator]))))
(defn render-row-fn [row _ _]
(rn/list-item
[rn/touchable-highlight {:on-press #(rf/dispatch [:navigate-to-modal :transaction-details row])}
[rn/view
[transactions-list-item/view row]]]))
(defview unsigned-transactions []
[transactions [:transactions]
{:keys [password]} [:get :confirm-transactions]
confirmed? [:get-in [:transactions-list-ui-props :confirmed?]]
sync-state [:sync-state]
network-status [:get :network-status]]
{:component-did-update #(when-not (seq transactions) (rf/dispatch [:navigate-back]))
:component-will-unmount #(rf/dispatch [:set-in [:transactions-list-ui-props :confirmed?] false])}
(let [offline? (or (= network-status :offline) (= sync-state :offline))]
[rn/keyboard-avoiding-view st/transactions-screen
[status-bar/status-bar {:type :transaction}]
[toolbar-view transactions]
[rn/view {:style st/transactions-screen-content-container}
[rn/list-view {:style st/transactions-list
:dataSource (lw/to-datasource transactions)
:renderSeparator (render-separator-fn (count transactions))
:renderRow render-row-fn}]
(when (and confirmed? (not offline?))
[password-form/view (count transactions)])]
(when-not offline?
(let [confirm-text (if confirmed?
(i18n/label :t/confirm)
(i18n/label-pluralize (count transactions) :t/confirm-transactions))
confirm-fn (if confirmed?
#(do (rf/dispatch [:accept-transactions password])
(rf/dispatch [:set :confirmed-transactions-count (count transactions)]))
#(rf/dispatch [:set-in [:transactions-list-ui-props :confirmed?] true]))]
[sticky-button/sticky-button confirm-text confirm-fn true]))
[offline-view/offline-view {:top (if platform/ios? 21 0)}]]))

View File

@ -1,12 +0,0 @@
(ns status-im.transactions.specs
(:require [cljs.spec.alpha :as s]))
(s/def :transactions/transactions (s/nilable map?)) ;; {id (string) transaction (map)}
(s/def :transactions/transactions-queue (s/nilable map?)) ;; {id (string) transaction (map)}
(s/def :transactions/selected-transaction (s/nilable map?))
(s/def :transactions/confirm-transactions (s/nilable map?))
(s/def :transactions/confirmed-transactions-count (s/nilable int?))
(s/def :transactions/transactions-list-ui-props (s/nilable map?))
(s/def :transactions/transaction-details-ui-props (s/nilable map?))
(s/def :transactions/wrong-password-counter (s/nilable int?))
(s/def :transactions/wrong-password? (s/nilable boolean?))

View File

@ -1,52 +0,0 @@
(ns status-im.transactions.styles.list-item
(:require-macros [status-im.utils.styles :refer [defstyle]])
(:require [status-im.components.styles :as st]))
(def item
{:padding-vertical 19
:padding-horizontal 16
:flex 1
:flex-direction :row
:align-items :center})
(def item-photo
{:width 86
:height 48
:border-radius 100
:background-color st/color-dark-blue-3
:flex-direction :row
:align-items :center})
(def item-info
{:margin-left 16
:flex 1})
(defstyle item-info-recipient
{:color st/color-light-blue
:font-size 15
:flex-shrink 1
:android {:margin-bottom 5}
:ios {:margin-bottom 4}})
(defstyle item-info-amount
{:color st/color-white
:android {:font-size 19}
:ios {:font-size 20}})
(def item-deny-btn
{:margin-left 16})
(def item-deny-btn-icon
{:width 24
:height 24})
(def photo-size 48)
(def photo-placeholder
{:width 48
:height 48})
(def item-photo-icon
{:margin-left 4
:width 24
:height 24})

View File

@ -1,9 +0,0 @@
(ns status-im.transactions.styles.password-form
(:require-macros [status-im.utils.styles :refer [defstyle]])
(:require [status-im.components.styles :as common]))
(defstyle password-container
{:android {:margin-bottom 27}
:ios {:margin-bottom 20
:border-top-width 1
:border-top-color common/color-white-transparent-2}})

View File

@ -1,134 +0,0 @@
(ns status-im.transactions.styles.screens
(:require-macros [status-im.utils.styles :refer [defstyle]])
(:require [status-im.components.styles :as common]
[status-im.utils.platform :as platform]))
;; common
(def transactions-toolbar-background (if platform/ios?
common/color-dark-blue-2
common/color-dark-blue-1))
(defstyle toolbar-title-container
{:flex 1
:flex-direction :row
:padding-left 18
:ios {:align-items :center
:justify-content :center}})
(def toolbar-title-text
{:color common/color-white
:font-size 17})
(defstyle toolbar-title-count
{:color common/color-white
:font-size 17
:margin-left 8
:android {:opacity 0.2}
:ios {:opacity 0.6}})
(defstyle toolbar-border
{:ios {:background-color common/color-white
:opacity 0.1}})
;; unsigned-transactions
(def transactions-screen
{:flex 1
:background-color common/color-dark-blue-2})
(def transactions-screen-content-container
{:flex 1
:justify-content :space-between})
(defstyle transactions-list
{:flex 1
:android {:padding-vertical 8}})
(def transactions-list-separator
{:margin-left 16
:opacity 0.1})
;; transaction-details
(defstyle details-screen-content-container
{:flex 1
:android {:padding-top 8}})
(def details-separator-wrapper
{:background-color common/color-dark-blue-2})
(def details-separator
{:margin-left 16
:background-color common/color-white
:opacity 0.1})
(defstyle details-container
{:ios {:margin-top 10}
:android {:margin-top 0}})
(def details-item
{:margin-top 10
:padding-left 16
:padding-right 16
:flex-direction :row})
(defstyle details-item-title
{:width 80
:font-size 15
:color common/color-white
:android {:opacity 0.2
:margin-right 24}
:ios {:opacity 0.5
:margin-right 8
:text-align :right}})
(defn details-item-content [name?]
{:font-size 15
:flex-shrink 1
:color (if name? common/color-light-blue common/color-white)})
(defstyle details-data
{:padding 16
:margin-top 16
:background-color common/color-dark-blue-3
:ios {:margin-horizontal 16}})
(defstyle details-data-title
{:font-size 15
:color common/color-white
:android {:opacity 0.2}
:ios {:opacity 0.5}})
(def details-data-content
{:font-size 15
:color common/color-white
:margin-top 8})
;; confirmation-success
(def success-screen
{:flex 1
:background-color common/color-dark-blue-2})
(def success-screen-content-container
{:flex 1
:align-items :center
:justify-content :center})
(def success-icon-container
{:background-color common/color-light-blue
:border-radius 100
:height 133
:width 133
:justify-content :center
:align-items :center})
(def success-icon
{:height 40
:width 54})
(def success-text
{:font-size 17
:color common/color-light-blue3
:margin-top 26})

View File

@ -1,24 +0,0 @@
(ns status-im.transactions.subs
(:require [re-frame.core :refer [reg-sub subscribe]]
[status-im.utils.hex :as i]))
(reg-sub :transactions
(fn [db]
(vals (:transactions db))))
(reg-sub :contacts-by-address
(fn [db]
(into {} (map (fn [[_ {:keys [address] :as contact}]]
(when address
[address contact]))
(:contacts/contacts db)))))
(reg-sub :contact-by-address
:<- [:contacts-by-address]
(fn [contacts [_ address]]
(let [address' (when address
(i/normalize-hex address))]
(contacts address'))))
(reg-sub :wrong-password?
(fn [db] (:wrong-password? db)))

View File

@ -1,40 +0,0 @@
(ns status-im.transactions.views.list-item
(:require-macros [status-im.utils.views :refer [defview]])
(:require [re-frame.core :as rf]
[status-im.components.chat-icon.screen :as chat-icon]
[status-im.components.react :as rn]
[status-im.i18n :as i18n]
[status-im.transactions.styles.list-item :as st]
[status-im.utils.money :as money]))
(defview item-image [contact]
[rn/view {:style st/item-photo}
(if-not (empty? contact)
[chat-icon/chat-icon (:photo-path contact) {:size st/photo-size}]
[rn/view {:style st/photo-placeholder}])
[rn/image {:source {:uri :icon_arrow_left_white}
:style st/item-photo-icon}]])
(defn item-info [recipient-name value]
[rn/view {:style st/item-info}
[rn/text {:style st/item-info-recipient
:number-of-lines 1}
recipient-name]
[rn/text {:style st/item-info-amount} value]])
(defn deny-btn [transaction-id on-deny]
[rn/touchable-highlight {:on-press #(do (rf/dispatch [:deny-transaction transaction-id])
(when on-deny (on-deny)))}
[rn/view {:style st/item-deny-btn}
[rn/image {:source {:uri :icon_close_white}
:style st/item-deny-btn-icon}]]])
(defview view [{:keys [to value id] :as transaction} on-deny]
[recipient [:contact-by-address to]]
(let [eth-value (str (money/wei->ether value))
value-str (str (i18n/label-number eth-value) " ETH")
recipient-name (or (:name recipient) to (i18n/label :t/contract-creation))]
[rn/view {:style st/item}
[item-image recipient]
[item-info recipient-name value-str]
[deny-btn id on-deny]]))

View File

@ -1,21 +0,0 @@
(ns status-im.transactions.views.password-form
(:require-macros [status-im.utils.views :refer [defview]])
(:require [re-frame.core :as rf]
[status-im.components.react :as rn]
[status-im.components.text-input-with-label.view :refer [text-input-with-label]]
[status-im.transactions.styles.password-form :as st]
[status-im.i18n :as i18n]))
(defview view [transaction-quantity]
[wrong-password? [:wrong-password?]]
(let [error? wrong-password?]
[rn/view st/password-container
[text-input-with-label
{:label (i18n/label :t/password)
:description (i18n/label-pluralize transaction-quantity :t/enter-password-transactions)
:on-change-text #(rf/dispatch [:set-in [:confirm-transactions :password] %])
:style {:color :white}
:auto-focus true
:secure-text-entry true
:error (when error? (i18n/label :t/wrong-password))}]]))

View File

@ -10,7 +10,6 @@
status-im.chat.specs
status-im.chat.new-public-chat.db
status-im.ui.screens.profile.db
status-im.transactions.specs
status-im.ui.screens.discover.db
status-im.ui.screens.network-settings.db))
@ -172,15 +171,6 @@
:chat/raw-unviewed-messages
:chat/bot-db
:chat/geolocation
:transactions/transactions
:transactions/transactions-queue
:transactions/selected-transaction
:transactions/confirm-transactions
:transactions/confirmed-transactions-count
:transactions/transactions-list-ui-props
:transactions/transaction-details-ui-props
:transactions/wrong-password-counter
:transactions/wrong-password?
:discoveries/discoveries
:discoveries/discover-search-tags
:discoveries/tags

View File

@ -6,7 +6,6 @@
status-im.debug.handlers
status-im.network.handlers
status-im.protocol.handlers
status-im.transactions.handlers
status-im.ui.screens.accounts.events
status-im.ui.screens.contacts.events
status-im.ui.screens.discover.events
@ -18,6 +17,8 @@
status-im.ui.screens.qr-scanner.events
status-im.ui.screens.wallet.events
status-im.ui.screens.wallet.send.events
status-im.ui.screens.wallet.choose-recipient.events
status-im.ui.screens.wallet.transactions.events
[re-frame.core :refer [dispatch reg-fx reg-cofx] :as re-frame]
[status-im.native-module.core :as status]
[status-im.components.permissions :as permissions]
@ -348,10 +349,10 @@
(register-handler-fx
:app-state-change
(fn [_ [_ state]]
(fn [_ [_ state]]))
;; TODO(rasom): let's not remove this handler, it will be used for
;; pausing node on entering background on android
))
(register-handler-fx
:request-permissions

View File

@ -13,7 +13,6 @@
status-im.ui.screens.wallet.send.subs
status-im.ui.screens.wallet.request.subs
status-im.ui.screens.network-settings.subs
status-im.transactions.subs
status-im.bots.subs))
(reg-sub :get

View File

@ -21,11 +21,6 @@
[status-im.ui.screens.qr-scanner.views :refer [qr-scanner]]
[status-im.transactions.screens.confirmation-success :refer [confirmation-success]]
[status-im.transactions.screens.unsigned-transactions :refer [unsigned-transactions]]
[status-im.transactions.screens.transaction-details :refer [transaction-details]]
[status-im.ui.screens.group.views :refer [new-group edit-contact-group]]
[status-im.ui.screens.group.chat-settings.views :refer [chat-group-settings]]
[status-im.ui.screens.group.edit-contacts.views :refer [edit-contact-group-contact-list
@ -40,7 +35,7 @@
[status-im.ui.screens.profile.photo-capture.views :refer [profile-photo-capture]]
[status-im.ui.screens.profile.qr-code.views :refer [qr-code-view]]
[status-im.ui.screens.wallet.send.views :refer [send-transaction]]
[status-im.ui.screens.wallet.send.views :refer [send-transaction send-transaction-modal]]
[status-im.ui.screens.wallet.choose-recipient.views :refer [choose-recipient]]
[status-im.ui.screens.wallet.request.views :refer [request-transaction]]
[status-im.ui.screens.wallet.wallet-list.views :refer [wallet-list-screen]]
@ -109,8 +104,6 @@
:add-rpc-url add-rpc-url
:network-details network-details
(throw (str "Unknown view: " current-view)))]
[(if android? menu-context view) common-styles/flex
[view common-styles/flex
[component]
@ -122,11 +115,8 @@
(let [component (case modal-view
:qr-scanner qr-scanner
:qr-code-view qr-code-view
:unsigned-transactions unsigned-transactions
:transaction-details transaction-details
:confirmation-success confirmation-success
:contact-list-modal contact-list-modal
:wallet-transactions-filter wallet-transactions/filter-history
:wallet-transactions-sign-all wallet-transactions/sign-all
:wallet-send-transaction-modal send-transaction-modal
(throw (str "Unknown modal view: " modal-view)))]
[component])]])]])))))

View File

@ -0,0 +1,26 @@
(ns status-im.ui.screens.wallet.choose-recipient.events
(:require [status-im.utils.handlers :as handlers]))
(handlers/register-handler-db
:wallet/toggle-flashlight
(fn [db]
(let [flashlight-state (get-in db [:wallet/send-transaction :camera-flashlight])
toggled-state (if (= :on flashlight-state) :off :on)]
(assoc-in db [:wallet/send-transaction :camera-flashlight] toggled-state))))
(defn choose-address-and-name [db address name]
(update db :wallet/send-transaction assoc :to-address address :to-name name))
(handlers/register-handler-fx
:choose-recipient
(fn [{:keys [db]} [_ address name]]
(let [{:keys [view-id]} db]
(cond-> {:db (choose-address-and-name db address name)}
(= :choose-recipient view-id) (assoc :dispatch [:navigate-back])))))
(handlers/register-handler-fx
:wallet-open-send-transaction
(fn [{db :db} [_ address name]]
{:db (choose-address-and-name db address name)
:dispatch-n [[:navigate-back]
[:navigate-back]]}))

View File

@ -21,7 +21,7 @@
:line-height 12}})
(def amount-text-input-container
{:margin-top 8})
{:margin-top 8})
(def label-transparent
(merge label
@ -61,6 +61,14 @@
:ios {:border-radius 8}
:android {:border-radius 4}})
(defstyle container-disabled
{:border-width 1
:border-color styles/color-white-transparent-4
:background-color nil
:ios {:border-radius 8}
:android {:border-radius 4}})
(defstyle recipient-container
{:flex-direction :row
:flex 1

View File

@ -21,6 +21,17 @@
[react/text {:style styles/tooltip-text} label]]
[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 []
(let [active? (reagent/atom false)]
(fn [& [{:keys [input-options style error]}]]
@ -53,6 +64,22 @@
style)
[react/text {:style styles/wallet-name} "ETH"]]])
(defn choose-recipient-disabled [{:keys [address name]}]
[react/view
[react/text {:style styles/label} (i18n/label :t/recipient)]
[react/view (merge styles/recipient-container
styles/container-disabled)
(when name
[react/view styles/recipient-name-container
[react/text {:style (styles/participant true)
:number-of-lines 1}
name]])
[react/view components.styles/flex
[react/text {:style (styles/participant (not name))
:number-of-lines 1
:ellipsizeMode :middle}
address]]]])
(defn choose-recipient [{:keys [address name on-press style]}]
(let [address? (and (not (nil? address)) (not= address ""))]
[react/touchable-highlight {:on-press on-press}

View File

@ -136,3 +136,8 @@
(fn [{:keys [db]} [_ hash]]
{:db (assoc-in db [:wallet :current-transaction] hash)
:dispatch [:navigate-to :wallet-transaction-details]}))
(handlers/register-handler-fx
:wallet/discard-unsigned-transaction
(fn [_ [_ transaction-id]]
{:discard-transaction transaction-id}))

View File

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

View File

@ -7,6 +7,7 @@
(spec/def ::to-name (spec/nilable string?))
(spec/def ::amount-error (spec/nilable string?))
(spec/def ::password (spec/nilable string?))
(spec/def ::wrong-password? (spec/nilable boolean?))
(spec/def ::transaction-id (spec/nilable string?))
(spec/def ::waiting-signal? (spec/nilable boolean?))
(spec/def ::signing? (spec/nilable boolean?))
@ -17,5 +18,5 @@
(spec/def ::camera-flashlight #{:on :off})
(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 ::wrong-password?
::waiting-signal? ::signing? ::transaction-id ::later? ::camera-dimensions ::camera-flashlight]))

View File

@ -30,66 +30,58 @@
(fn []
(utils/show-popup (i18n/label :t/transaction-moved-title) (i18n/label :t/transaction-moved-text))))
(re-frame/reg-fx
::discard-transaction
(fn [id]
(status/discard-transaction id)))
;;;; Handlers
(defn choose-address-and-name [db address name]
(update db :wallet/send-transaction assoc :to-address address :to-name name))
(handlers/register-handler-fx
:choose-recipient
(fn [{:keys [db]} [_ address name]]
(let [{:keys [view-id]} db]
(cond-> {:db (choose-address-and-name db address name)}
(= :choose-recipient view-id) (assoc :dispatch [:navigate-back])))))
(handlers/register-handler-fx
:wallet-open-send-transaction
(fn [{db :db} [_ address name]]
{:db (choose-address-and-name db address name)
:dispatch-n [[:navigate-back]
[:navigate-back]]}))
(handlers/register-handler-fx
:wallet-validate-amount
(fn [{{:keys [web3] :wallet/keys [send-transaction] :as db} :db} _]
(let [amount (:amount send-transaction)
error (wallet.db/get-amount-validation-error amount web3)]
{:db (assoc-in db [:wallet/send-transaction :amount-error] error)})))
:wallet/set-and-validate-amount
(fn [{{:keys [web3] :wallet/keys [send-transaction] :as db} :db} [_ amount]]
(let [error (wallet.db/get-amount-validation-error amount web3)]
{:db (-> db
(assoc-in [:wallet/send-transaction :amount] amount)
(assoc-in [:wallet/send-transaction :amount-error] error))})))
(handlers/register-handler-fx
::transaction-completed
(fn [{db :db} [_ {:keys [id response]}]]
(let [{:keys [hash error]} response]
;; error is handling in TRANSACTION FAILED signal from status-go
(when-not (and error (string? error) (not (string/blank? error)))
{:db (-> db
(update-in [:wallet :transactions-unsigned] dissoc id)
(assoc-in [:wallet/send-transaction :transaction-id] nil)
(assoc :wrong-password? false))
(assoc-in [:wallet/send-transaction :wrong-password?] false))
:dispatch [:navigate-to :wallet-transaction-sent]}))))
(defn on-transactions-completed [raw-results]
(let [results (:results (types/json->clj raw-results))]
(doseq [result results]
;;TODO (andrey) legacy, should be removed with old transactions screens
(re-frame/dispatch [:transaction-completed {:id (name (key result)) :response (second result)}])
(re-frame/dispatch [::transaction-completed {:id (name (key result)) :response (second result)}]))))
(handlers/register-handler-fx
:wallet/transaction-queued
(fn [{{:wallet/keys [send-transaction] :as db} :db} [_ transaction-id]]
(let [{:keys [later? password]} send-transaction]
::transaction-modal-completed
(fn [{db :db} [_ {:keys [id response]}]]
(let [{:keys [hash error]} response]
(when-not (and error (string? error) (not (string/blank? error)))
{:db (-> db
(update-in [:wallet :transactions-unsigned] dissoc id)
(assoc-in [:wallet/send-transaction :transaction-id] nil)
(assoc-in [:wallet/send-transaction :wrong-password?] false))
:dispatch [:navigate-back]}))))
(defn on-transactions-modal-completed [raw-results]
(let [results (:results (types/json->clj raw-results))]
(doseq [result results]
(re-frame/dispatch [::transaction-modal-completed {:id (name (key result)) :response (second result)}]))))
(handlers/register-handler-fx
:wallet.send-transaction/transaction-queued
(fn [{{:wallet/keys [send-transaction] :as db} :db} _]
(let [{:keys [later? password transaction-id]} send-transaction]
(if later?
{:db (-> db
(assoc-in [:wallet/send-transaction :waiting-signal?] false)
(assoc :transactions (:transactions-queue db)))
{:db (assoc-in db [:wallet/send-transaction :waiting-signal?] false)
:dispatch [:navigate-back]
::show-transaction-moved nil}
{:db (assoc-in db [:wallet/send-transaction :transaction-id] transaction-id)
::accept-transaction {:id transaction-id
{::accept-transaction {:id transaction-id
:password password
:on-completed on-transactions-completed}}))))
@ -112,22 +104,30 @@
:to (:to-address send-transaction)
:value amount-in-wei}}))))
(handlers/register-handler-fx
:wallet/sign-transaction-modal
(fn [{{:keys [web3]
:wallet/keys [send-transaction]
:accounts/keys [accounts current-account-id] :as db} :db} [_ later?]]
(let [{:keys [amount transaction-id password]} send-transaction
amount' (money/to-wei (string/replace amount #"," "."))]
{::accept-transaction {:id transaction-id
:password password
:on-completed on-transactions-modal-completed}})))
(handlers/register-handler-fx
:wallet/discard-transaction
(fn [{{:wallet/keys [send-transaction] :as db} :db} _]
(let [{:keys [transaction-id]} send-transaction]
(merge {:db (-> db
(update-in [:wallet/send-transaction]
#(assoc % :signing? false :transaction-id nil))
(assoc :wrong-password? false))}
#(assoc % :signing? false :transaction-id nil :wrong-password? false)))}
(when transaction-id
;;TODO (andrey) use ::discard-transaction fx instead
{:dispatch-n [[:deny-transaction transaction-id]
[:status-im.transactions.handlers/remove-transaction transaction-id]]})))))
{:discard-transaction transaction-id})))))
(handlers/register-handler-db
:wallet/toggle-flashlight
(fn [db]
(let [flashlight-state (get-in db [:wallet/send-transaction :camera-flashlight])
toggled-state (if (= :on flashlight-state) :off :on)]
(assoc-in db [:wallet/send-transaction :camera-flashlight] toggled-state))))
(handlers/register-handler-fx
:wallet/cancel-signing-modal
(fn [{{:wallet/keys [send-transaction] :as db} :db} _]
(let [{:keys [transaction-id]} send-transaction]
{:db (update-in db [:wallet/send-transaction]
assoc :signing? false :wrong-password? false)})))

View File

@ -36,8 +36,7 @@
(defview sign-panel []
(letsubs [account [:get-current-account]
;;TODO (andrey) use send-transaction map after we remove old transactions ui
wrong-password? [:get :wrong-password?];[:get-in [:wallet/send-transaction :wrong-password?]]
wrong-password? [:get-in [:wallet/send-transaction :wrong-password?]]
signing-phrase (:signing-phrase @account)
bottom-value (animation/create-value -250)
opacity-value (animation/create-value 0)]
@ -58,14 +57,16 @@
(when wrong-password?
[components/tooltip (i18n/label :t/wrong-password)])]))
(defview signing-buttons []
;; "Cancel" and "Sign Transaction >" buttons, signing with password
(defview signing-buttons [cancel-handler sign-handler]
(letsubs [sign-enabled? [:wallet.send/sign-password-enabled?]]
[react/view wallet.styles/buttons-container
[react/touchable-highlight {:on-press #(re-frame/dispatch [:wallet/discard-transaction])}
[react/touchable-highlight {:on-press cancel-handler}
[react/view (wallet.styles/button-container true)
[components/button-text (i18n/label :t/cancel)]]]
[react/view components.styles/flex]
[react/touchable-highlight {:on-press #(re-frame/dispatch [:wallet/sign-transaction])}
[react/touchable-highlight {:on-press sign-handler}
[react/view (wallet.styles/button-container sign-enabled?)
[components/button-text (i18n/label :t/transactions-sign-transaction)]
[vector-icons/icon :icons/forward {:color :white :container-style wallet.styles/forward-icon-container}]]]]))
@ -76,12 +77,13 @@
(not (nil? to-address)) (not= to-address "")
(not (nil? amount)) (not= amount "")))
(defn- sign-buttons [amount-error to-address amount sufficient-funds?]
;; "Sign Later" and "Sign Transaction >" buttons
(defn- sign-buttons [amount-error to-address amount sufficient-funds? sign-later-handler]
(let [sign-enabled? (sign-enabled? amount-error to-address amount)
immediate-sign-enabled? (and sign-enabled? sufficient-funds?)]
[react/view wallet.styles/buttons-container
(when sign-enabled?
[react/touchable-highlight {:on-press sign-later}
[react/touchable-highlight {:on-press sign-later-handler}
[react/view (wallet.styles/button-container sign-enabled?)
[components/button-text (i18n/label :t/transactions-sign-later)]]])
[react/view components.styles/flex]
@ -119,13 +121,50 @@
:input-options {:auto-focus true
:default-value amount
:on-change-text #(let [value (string/trim %)]
(re-frame/dispatch [:set-in [:wallet/send-transaction :amount] value])
(re-frame/dispatch [:wallet-validate-amount]))}}]
(re-frame/dispatch [:wallet/set-and-validate-amount value]))}}]
[react/view wallet.styles/choose-currency-container
[components/choose-currency wallet.styles/choose-currency]]]]]
[components/separator]
(if signing?
[signing-buttons]
[sign-buttons amount-error to-address amount sufficient-funds?])
[signing-buttons
#(re-frame/dispatch [:wallet/discard-transaction])
#(re-frame/dispatch [:wallet/sign-transaction])]
[sign-buttons amount-error to-address amount sufficient-funds? sign-later])
(when signing?
[sign-panel])]])))
[sign-panel])]])))
(defn toolbar-modal []
[toolbar/toolbar2 {:style wallet.styles/toolbar}
[toolbar/nav-button (act/close-white act/default-handler)]
[toolbar/content-title {:color :white} (i18n/label :t/send-transaction)]])
(defview send-transaction-modal []
(letsubs [amount [:get-in [:wallet/send-transaction :amount]]
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]]
recipient [:contact-by-address @to-name]]
[react/keyboard-avoiding-view wallet.styles/wallet-modal-container
[react/view components.styles/flex
[status-bar/status-bar {:type :wallet}]
[toolbar-modal]
[react/scroll-view {:keyboardShouldPersistTaps :always}
[react/view components.styles/flex
[react/view wallet.styles/choose-participant-container
[components/choose-recipient-disabled {:address to-address
:name (:name recipient)}]]
[react/view wallet.styles/choose-wallet-container
[components/choose-wallet]]
[react/view wallet.styles/amount-container
[components/amount-input-disabled amount]
[react/view wallet.styles/choose-currency-container
[components/choose-currency wallet.styles/choose-currency]]]]]
[components/separator]
(if signing?
[signing-buttons
#(re-frame/dispatch [:wallet/cancel-signing-modal])
#(re-frame/dispatch [:wallet/sign-transaction-modal])]
[sign-buttons amount-error to-address amount true #(re-frame/dispatch [:navigate-back])])
(when signing?
[sign-panel])]]))

View File

@ -0,0 +1,77 @@
(ns status-im.ui.screens.wallet.transactions.events
(:require [status-im.utils.handlers :as handlers]
[status-im.constants :as constants]
[status-im.utils.money :as money]
[status-im.native-module.core :as status]
[re-frame.core :as re-frame]
[status-im.utils.hex :as utils.hex]
[clojure.string :as string]))
;;FX
(re-frame/reg-fx
:discard-transaction
(fn [id]
(status/discard-transaction id)))
;;Helper functions
(defn transaction-valid? [{{:keys [to data]} :args}]
(or (and to (utils.hex/valid-hex? to)) (and data (not= data "0x"))))
;;Handlers
;TRANSACTION QUEUED signal from status-go
(handlers/register-handler-fx
:transaction-queued
[(re-frame/inject-cofx :now)]
(fn [{{:wallet/keys [send-transaction] :as db} :db now :now} [_ {:keys [id message_id args] :as transaction}]]
(if (transaction-valid? transaction)
(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)
transaction {:id id
:from from
:to to
:value (money/to-decimal value)
:data data
:gas (money/to-decimal gas)
:gas-price (money/to-decimal gasPrice)
:timestamp now
:message-id message_id}]
(merge
{:db (-> db
(assoc-in [:wallet :transactions-unsigned id] transaction)
(assoc-in [:wallet/send-transaction :transaction-id] id))}
(if (:waiting-signal? send-transaction)
;;sending from wallet
{:dispatch [:wallet.send-transaction/transaction-queued id]}
;;sending from chat
{:dispatch [:navigate-to-modal :wallet-send-transaction-modal {:amount (str (money/wei->ether value))
:transaction-id id
:to-address to
:to-name to}]}))))
{:discard-transaction id})))
;TRANSACTION FAILED signal from status-go
(handlers/register-handler-fx
:transaction-failed
(fn [{{:accounts/keys [accounts current-account-id] :as db} :db} [_ {:keys [id args message_id error_code error_message] :as event}]]
(let [current-account-address (:address (get accounts current-account-id))
transaction-initiator-address (utils.hex/normalize-hex (:from args))]
(case error_code
;;WRONG PASSWORD
constants/send-transaction-password-error-code
{:db (assoc-in db [:wallet/send-transaction :wrong-password?] true)}
;;TODO (andrey) something weird here below, revisit
;;DISCARDED
constants/send-transaction-discarded-error-code
{:db (update-in db [:wallet :transactions-unsigned] dissoc id)
:dispatch [:set-chat-ui-props {:validation-messages nil}]}
;;NO ERROR, TIMEOUT or DEFAULT ERROR
(merge
{:db (update-in db [:wallet :transactions-unsigned] dissoc id)}
(when (and message_id (= current-account-address transaction-initiator-address))
{:dispatch [:set-chat-ui-props {:validation-messages error_message}]}))))))

View File

@ -3,7 +3,8 @@
[status-im.i18n :as i18n]
[status-im.utils.datetime :as datetime]
[status-im.utils.money :as money]
[status-im.utils.transactions :as transactions]))
[status-im.utils.transactions :as transactions]
[status-im.utils.hex :as utils.hex]))
(reg-sub :wallet.transactions/transactions-loading?
:<- [:wallet]
@ -25,18 +26,23 @@
(fn [transactions]
(group-by :type (vals transactions))))
(defn format-unsigned-transaction [{:keys [message-id gas-price] :as transaction}]
(defn format-unsigned-transaction [{:keys [id] :as transaction}]
(assoc transaction
:type :unsigned
:confirmations 0
:symbol "ETH"
:hash message-id))
;; TODO (andrey) revisit this, we shouldn't set not hash value to the hash field
:hash id))
(reg-sub :wallet/unsigned-transactions
(fn [db]
(vals (get-in db [:wallet :transactions-unsigned]))))
(reg-sub :wallet.transactions/unsigned-transactions
:<- [:transactions]
:<- [:wallet/unsigned-transactions]
(fn [transactions]
(reduce (fn [acc {:keys [message-id] :as transaction}]
(assoc acc message-id (format-unsigned-transaction transaction)))
(reduce (fn [acc {:keys [id] :as transaction}]
(assoc acc id (format-unsigned-transaction transaction)))
{}
transactions)))
@ -134,3 +140,19 @@
(if (>= confirmations max-confirmations)
100
(* 100 (/ confirmations max-confirmations))))))
(reg-sub
:contacts-by-address
(fn [db]
(into {} (map (fn [[_ {:keys [address] :as contact}]]
(when address
[address contact]))
(:contacts/contacts db)))))
(reg-sub
:contact-by-address
:<- [:contacts-by-address]
(fn [contacts [_ address]]
(let [address' (when address
(utils.hex/normalize-hex address))]
(contacts address'))))

View File

@ -26,10 +26,11 @@
(re-frame/dispatch [:accept-transactions password]))
(defn on-delete-transaction
[m]
;; TODO(yenda) implement
(utils/show-popup "TODO" "Delete Transaction"))
[{:keys [id]}]
;; TODO(andrey) implement alert
(re-frame/dispatch [:wallet/discard-unsigned-transaction id]))
;; TODO (andrey) implement
(defn unsigned-action [unsigned-transactions-count]
[toolbar/text-action {:disabled? (zero? unsigned-transactions-count)
:handler #(re-frame/dispatch [:navigate-to-modal :wallet-transactions-sign-all])}
@ -45,37 +46,24 @@
[toolbar/content-title (i18n/label :t/transactions)]
(case @view-id
:wallet-transactions-unsigned
[unsigned-action unsigned-transactions-count]
nil ;; TODO (andrey) implement [unsigned-action unsigned-transactions-count]
:wallet-transactions-history
[toolbar/actions
[history-action]])])
;; Sign all
(defview sign-all []
[]
[react/keyboard-avoiding-view {:style transactions.styles/sign-all-view}
[react/view {:style transactions.styles/sign-all-done}
[button/primary-button {:style transactions.styles/sign-all-done-button
:text (i18n/label :t/done)
:on-press #(re-frame/dispatch [:navigate-back])}]]
[react/view {:style transactions.styles/sign-all-popup}
[react/text {:style transactions.styles/sign-all-popup-sign-phrase} "one two three"] ;; TODO hook
[react/text {:style transactions.styles/sign-all-popup-text} (i18n/label :t/transactions-sign-all-text)]
[react/view {:style transactions.styles/sign-all-actions}
[react/text-input {:style transactions.styles/sign-all-input
:secure-text-entry true
:placeholder (i18n/label :t/transactions-sign-input-placeholder)}]
[button/primary-button {:text (i18n/label :t/transactions-sign-all) :on-press #(println %)}]]]])
(defn action-buttons [m]
(defn action-buttons [{:keys [id to value] :as transaction}]
[react/view {:style transactions.styles/action-buttons}
[button/primary-button {:text (i18n/label :t/transactions-sign)
:style {:margin-right 12}
:on-press #(re-frame/dispatch [:navigate-to-modal :wallet-transactions-sign-all])}]
[button/secondary-button {:text (i18n/label :t/delete) :on-press #(on-delete-transaction m)}]])
[button/primary-button {:style {:margin-right 12}
:on-press #(re-frame/dispatch [:navigate-to-modal
:wallet-send-transaction-modal
{:amount (str (money/wei->ether value))
:transaction-id id
:to-address to
:to-name to}])}
(i18n/label :t/transactions-sign)]
[button/secondary-button {:on-press #(on-delete-transaction transaction)}
(i18n/label :t/delete)]])
(defn- inbound? [type] (= "inbound" type))
(defn- unsigned? [type] (= "unsigned" type))
@ -93,7 +81,7 @@
(:postponed :pending) (transaction-icon :icons/arrow-right styles/color-gray4-transparent styles/color-gray7)
(throw (str "Unknown transaction type: " k))))
(defn render-transaction [{:keys [hash to from type value symbol] :as m}]
(defn render-transaction [{:keys [hash to from type value symbol] :as transaction}]
[list/touchable-item #(re-frame/dispatch [:show-transaction-details hash])
[react/view
[list/item
@ -104,7 +92,7 @@
(str (i18n/label :t/from) " " from)
(str (i18n/label :t/to) " " to))
(when (unsigned? type)
[action-buttons m])]
[action-buttons transaction])]
[list/item-icon {:icon :icons/forward
:style {:margin-top 10}
:icon-opts transactions.styles/forward}]]]])
@ -259,14 +247,14 @@
{:text (i18n/label :t/open-on-etherscan) :value #(.openURL react/linking url)}])])
(defview transaction-details []
(letsubs [{:keys [hash url type] :as transactions} [:wallet.transactions/details]
(letsubs [{:keys [hash url type] :as transactions} [:wallet.transactions/transaction-details]
confirmations [:wallet.transactions.details/confirmations]
confirmations-progress [:wallet.transactions.details/confirmations-progress]]
[react/view {:style styles/flex}
[status-bar/status-bar]
[toolbar/toolbar2 {}
toolbar/default-nav-back
[toolbar/content-title (i18n/label :t/details)]
[toolbar/content-title (i18n/label :t/transaction-details)]
[toolbar/actions (details-action hash url)]]
[react/scroll-view {:style transactions.styles/main-section}
[details-header transactions]

View File

@ -26,6 +26,9 @@
(defn to-wei [str]
(dependencies/Web3.prototype.toWei str "ether"))
(defn to-decimal [value]
(dependencies/Web3.prototype.toDecimal value))
(def eth-units
{:wei (bignumber "1")
:kwei (bignumber "1000")