diff --git a/resources/js/bots/wallet/bot.js b/resources/js/bots/wallet/bot.js index 41f54acb82..f6d32279ff 100644 --- a/resources/js/bots/wallet/bot.js +++ b/resources/js/bots/wallet/bot.js @@ -352,26 +352,27 @@ function handleSend(params, context) { gasPrice: calculateGasPrice(params["bot-db"]["sliderValue"]) }; - web3.eth.sendTransaction(data, function(error, hash) { if (error) { - status.sendSignal("handler-data", { - status: "failed", - messageId: context["message-id"], - error: error + status.sendSignal("handler-result", { + status: "failed", + error: { + markup: status.components.validationMessage( + I18n.t('validation_tx_title'), + I18n.t('validation_tx_failed') + ) + }, + origParams: context["orig-params"] }); } else { - status.sendSignal("handler-data", { - status: "sent", - messageId: context["message-id"], - hash: hash + status.sendSignal("handler-result", { + status: "success", + hash: hash, + origParams: context["orig-params"] }); } }); - - return { - status: 'not-confirmed' - }; + // async handler, so we don't return anything immediately } function previewSend(params, context) { @@ -449,36 +450,6 @@ function previewSend(params, context) { } else { markup = [firstRow]; } - - if (!(context["handler-data"] - && context["handler-data"]["status"] === "sent")) { - var pendingRow = status.components.text( - { - style: { - color: "#9199a0", - fontSize: 12, - lineHeight: 18 - } - }, - I18n.t('send_transaction_pending') - ); - markup.push(pendingRow); - } - - if (context["handler-data"] - && context["handler-data"]["status"] === "failed") { - var errorRow = status.components.text( - { - style: { - color: "red", - fontSize: 12, - lineHeight: 18 - } - }, - I18n.t('send_transaction_failed') - ); - markup.push(errorRow); - } return { markup: status.components.view( @@ -512,6 +483,7 @@ var send = { params: paramsSend, validator: validateSend, handler: handleSend, + asyncHandler: true, preview: previewSend, shortPreview: shortPreviewSend }; diff --git a/resources/js/bots/wallet/translations.js b/resources/js/bots/wallet/translations.js index 0cfeb1b3ed..13af3ac9eb 100644 --- a/resources/js/bots/wallet/translations.js +++ b/resources/js/bots/wallet/translations.js @@ -14,8 +14,6 @@ I18n.translations = { send_explanation_3: 'probably within 30 seconds.', send_explanation_4: 'probably within a few seconds.', send_sending_to: 'to ', - send_transaction_pending: 'transaction pending', - send_transaction_failed: 'transaction failed', eth: 'ETH', @@ -25,6 +23,8 @@ I18n.translations = { request_requesting_from: 'from ', validation_title: 'Amount', + validation_tx_title: 'Transaction', + validation_tx_failed: 'Transaction failed', validation_amount_specified: 'Amount must be specified', validation_invalid_number: 'Amount is not valid number', validation_amount_is_too_small: 'Amount is too precise. The smallest unit you can send is 1 Wei (1x10^-18 ETH)', diff --git a/resources/js/status.js b/resources/js/status.js index 855c7ac15b..5412a0f151 100644 --- a/resources/js/status.js +++ b/resources/js/status.js @@ -27,6 +27,7 @@ Command.prototype.create = function (com) { this.description = com.description; this.handler = com.handler; this["has-handler"] = com.handler != null; + this["async-handler"] = (com.handler != null) && com.asyncHandler this["registered-only"] = com.registeredOnly; this.validator = com.validator; this.color = com.color; @@ -41,6 +42,7 @@ Command.prototype.create = function (com) { this["execute-immediately?"] = com.executeImmediately; this["sequential-params"] = com.sequentialParams; this["hide-send-button"] = com.hideSendButton; + this.addToCatalog(); return this; diff --git a/src/status_im/chat/events/commands.cljs b/src/status_im/chat/events/commands.cljs index c555c3f8df..1282c428ed 100644 --- a/src/status_im/chat/events/commands.cljs +++ b/src/status_im/chat/events/commands.cljs @@ -13,111 +13,110 @@ (defn generate-context "Generates context for jail call" - [{:keys [chats handler-data] :accounts/keys [current-account-id]} message-id chat-id to group-id] + [{:keys [chats] :accounts/keys [current-account-id]} chat-id to group-id] (merge {:platform platform/platform :from current-account-id :to to :chat {:chat-id chat-id :group-chat (or (get-in chats [chat-id :group-chat]) - (not (nil? group-id)))} - :handler-data (get handler-data message-id)} + (not (nil? group-id)))}} i18n/delimeters)) ;;;; Coeffects (reg-cofx - ::get-persisted-message - (fn [coeffects _] - (assoc coeffects :get-persisted-message msg-store/get-by-id))) + ::get-persisted-message + (fn [coeffects _] + (assoc coeffects :get-persisted-message msg-store/get-by-id))) ;;;; Effects (reg-fx - ::update-persisted-message - (fn [message] - (msg-store/update message))) + ::update-persisted-message + (fn [message] + (msg-store/update message))) (reg-fx - :chat-fx/call-jail - (fn [{:keys [callback-events-creator] :as opts}] - (status/call-jail - (-> opts - (dissoc :callback-events-creator) - (assoc :callback - (fn [jail-response] - (doseq [event (callback-events-creator jail-response)] - (dispatch event)))))))) + :chat-fx/call-jail + (fn [{:keys [callback-events-creator] :as opts}] + (status/call-jail + (-> opts + (dissoc :callback-events-creator) + (assoc :callback + (fn [jail-response] + (doseq [event (callback-events-creator jail-response)] + (dispatch event)))))))) ;;;; Handlers (register-handler-fx - ::jail-command-data-response - [trim-v] - (fn [{:keys [db]} [{{:keys [returned]} :result} {:keys [message-id on-requested]} data-type]] - (cond-> {} - returned - (assoc :db (assoc-in db [:message-data data-type message-id] returned)) - (and returned - (= :preview data-type)) - (assoc ::update-persisted-message {:message-id message-id - :preview (prn-str returned)}) - on-requested - (assoc :dispatch (on-requested returned))))) + ::jail-command-data-response + [trim-v] + (fn [{:keys [db]} [{{:keys [returned]} :result} {:keys [message-id on-requested]} data-type]] + (cond-> {} + returned + (assoc :db (assoc-in db [:message-data data-type message-id] returned)) + (and returned + (= :preview data-type)) + (assoc ::update-persisted-message {:message-id message-id + :preview (prn-str returned)}) + on-requested + (assoc :dispatch (on-requested returned))))) (register-handler-fx - :request-command-data - [trim-v] - (fn [{:keys [db]} - [{{:keys [command content-command params type]} :content - :keys [chat-id jail-id group-id message-id] :as message} - data-type]] - (let [{:keys [chats] - :accounts/keys [current-account-id] - :contacts/keys [contacts]} db - jail-id (or jail-id chat-id) - jail-id (if (get-in chats [jail-id :group-chat]) - (get-in chats [jail-id :command-suggestions (keyword command) :owner-id]) - jail-id)] - (if (get-in contacts [jail-id :commands-loaded?]) - (let [path [(if (= :response (keyword type)) :responses :commands) - (or content-command command) - data-type] - to (get-in contacts [chat-id :address]) - jail-params {:parameters params - :context (generate-context db message-id chat-id to group-id)}] - {:chat-fx/call-jail {:jail-id jail-id - :path path - :params jail-params - :callback-events-creator (fn [jail-response] - [[::jail-command-data-response - jail-response message data-type]])}}) - {:dispatch-n [[:add-commands-loading-callback jail-id - #(dispatch [:request-command-data message data-type])] - [:load-commands! jail-id]]})))) + :request-command-data + [trim-v] + (fn [{:keys [db]} + [{{:keys [command content-command params type]} :content + :keys [chat-id jail-id group-id message-id handler-data] :as message} + data-type]] + (let [{:keys [chats] + :accounts/keys [current-account-id] + :contacts/keys [contacts]} db + jail-id (or jail-id chat-id) + jail-id (if (get-in chats [jail-id :group-chat]) + (get-in chats [jail-id :command-suggestions (keyword command) :owner-id]) + jail-id)] + (if (get-in contacts [jail-id :commands-loaded?]) + (let [path [(if (= :response (keyword type)) :responses :commands) + (or content-command command) + data-type] + to (get-in contacts [chat-id :address]) + jail-params {:parameters params + :context (generate-context db chat-id to group-id)}] + {:chat-fx/call-jail {:jail-id jail-id + :path path + :params jail-params + :callback-events-creator (fn [jail-response] + [[::jail-command-data-response + jail-response message data-type]])}}) + {:dispatch-n [[:add-commands-loading-callback jail-id + #(dispatch [:request-command-data message data-type])] + [:load-commands! jail-id]]})))) (register-handler-fx - :execute-command-immediately - [trim-v] - (fn [_ [{command-name :name :as command}]] - (case (keyword command-name) - :grant-permissions - {:dispatch [:request-permissions - [:read-external-storage] - #(dispatch [:initialize-geth])]} - (log/debug "ignoring command: " command)))) + :execute-command-immediately + [trim-v] + (fn [_ [{command-name :name :as command}]] + (case (keyword command-name) + :grant-permissions + {:dispatch [:request-permissions + [:read-external-storage] + #(dispatch [:initialize-geth])]} + (log/debug "ignoring command: " command)))) (register-handler-fx - :request-command-preview - [trim-v (inject-cofx ::get-persisted-message)] - (fn [{:keys [db get-persisted-message]} [{:keys [message-id] :as message}]] - (let [previews (get-in db [:message-data :preview])] - (when-not (contains? previews message-id) - (let [{serialized-preview :preview} (get-persisted-message message-id)] - ;; if preview is already cached in db, do not request it from jail - ;; and write it directly to message-data path - (if serialized-preview - {:db (assoc-in db - [:message-data :preview message-id] - (reader/read-string serialized-preview))} - {:dispatch [:request-command-data message :preview]})))))) + :request-command-preview + [trim-v (inject-cofx ::get-persisted-message)] + (fn [{:keys [db get-persisted-message]} [{:keys [message-id] :as message}]] + (let [previews (get-in db [:message-data :preview])] + (when-not (contains? previews message-id) + (let [{serialized-preview :preview} (get-persisted-message message-id)] + ;; if preview is already cached in db, do not request it from jail + ;; and write it directly to message-data path + (if serialized-preview + {:db (assoc-in db + [:message-data :preview message-id] + (reader/read-string serialized-preview))} + {:dispatch [:request-command-data message :preview]})))))) diff --git a/src/status_im/chat/handlers/send_message.cljs b/src/status_im/chat/handlers/send_message.cljs index 6a0040a3fd..3850cf1db2 100644 --- a/src/status_im/chat/handlers/send_message.cljs +++ b/src/status_im/chat/handlers/send_message.cljs @@ -107,20 +107,9 @@ params' (assoc params :command content')] (dispatch [:prepare-command! wallet-chat-id params']))))))) -(register-handler ::check-preview-refetch - (fn [db [_ chat-id {:keys [message-id] :as message}]] - (let [handler-data (get-in db [:handler-data message-id])] - (if (:fetch-preview handler-data) - (do (dispatch [:request-command-data (assoc message :jail-id chat-id) :preview]) - (handler-data/save-data {:message-id message-id - :data (dissoc handler-data :fetch-preview)}) - (update-in db [:handler-data message-id] dissoc :fetch-preview)) - db)))) - (register-handler ::send-command! (u/side-effect! - (fn [_ [_ add-to-chat-id params hidden-params]] - (dispatch [::check-preview-refetch add-to-chat-id (:command params)]) + (fn [_ [_ add-to-chat-id params hidden-params]] (dispatch [::add-command add-to-chat-id params]) (dispatch [::save-command! add-to-chat-id params hidden-params]) (when (not= add-to-chat-id wallet-chat-id) @@ -163,11 +152,15 @@ to (get-in contacts [chat-id :address]) identity (or owner-id bot chat-id) bot-db (get bot-db (or bot chat-id)) + ;; TODO what's actually semantic difference between `:parameters` and `:context` + ;; and do we have some clear API for both ? seems very messy and unorganized now jail-params {:parameters params - :context {:from address - :to to - :current-account (get accounts current-account-id) - :message-id id}}] + :context (cond-> {:from address + :to to + :current-account (get accounts current-account-id) + :message-id id} + (:async-handler command) + (assoc :orig-params orig-params))}] (dispatch [:check-and-load-commands! identity @@ -175,8 +168,11 @@ {:jail-id identity :path [handler-type name :handler] :params jail-params - :callback (fn [res] - (dispatch [:command-handler! chat-id orig-params res]))})]))))) + :callback (if (:async-handler command) ; async handler, we ignore return value + (fn [_] + (log/debug "Async command handler called")) + (fn [res] + (dispatch [:command-handler! chat-id orig-params res])))})]))))) (register-handler :prepare-message (u/side-effect! diff --git a/src/status_im/commands/events/jail.cljs b/src/status_im/commands/events/jail.cljs deleted file mode 100644 index f449260316..0000000000 --- a/src/status_im/commands/events/jail.cljs +++ /dev/null @@ -1,31 +0,0 @@ -(ns status-im.commands.events.jail - (:require [re-frame.core :as re-frame] - [status-im.utils.handlers :as handlers] - [status-im.data-store.handler-data :as handler-data] - [taoensso.timbre :as log])) - -(re-frame/reg-fx - :save-handler-data - (fn [data] - (handler-data/save-data data))) - -(handlers/register-handler-fx - :set-handler-data - [re-frame/trim-v] - (fn [{:keys [db]} [chat-id {:keys [messageId] :as data}]] - (let [;; this is very bad, we should refactor our db ASAP - message (->> (get-in db [:chats chat-id :messages]) - (filter #(= (:message-id %) messageId)) - first) - handler-data (cond-> (dissoc data :messageId) - ;; message not there yet, indicate we want to re-fetch preview once it lands there - (nil? message) - (assoc :fetch-preview true)) - old-handler-data (get-in db [:handler-data messageId] {}) - new-handler-data (merge old-handler-data handler-data)] - (cond-> {:db (assoc-in db [:handler-data messageId] new-handler-data) - :save-handler-data {:message-id messageId - :data new-handler-data}} - ;; message was already added to db, we can re-fetch preview - (not (nil? message)) - (assoc :dispatch [:request-command-data (assoc message :jail-id chat-id) :preview]))))) diff --git a/src/status_im/commands/handlers/jail.cljs b/src/status_im/commands/handlers/jail.cljs index 38a0de938a..face714491 100644 --- a/src/status_im/commands/handlers/jail.cljs +++ b/src/status_im/commands/handlers/jail.cljs @@ -10,14 +10,13 @@ [status-im.constants :refer [console-chat-id]] [status-im.i18n :refer [get-contact-translated]] [taoensso.timbre :as log] - [status-im.data-store.local-storage :as local-storage] - status-im.commands.events.jail)) + [status-im.data-store.local-storage :as local-storage])) (defn command-handler! [_ [chat-id {:keys [command] :as params} {:keys [result error]}]] - (let [{:keys [context returned]} result + (let [{:keys [returned]} result {handler-error :error} returned] (cond handler-error @@ -26,10 +25,8 @@ result (let [command' (assoc command :handler-data returned) - params' (assoc params :command command')] - (if (:eth_sendTransaction context) - (dispatch [:wait-for-transaction (:id command) params']) - (dispatch [:prepare-command! chat-id params']))) + params' (assoc params :command command')] + (dispatch [:prepare-command! chat-id params'])) (not (or error handler-error)) (dispatch [:prepare-command! chat-id params]) diff --git a/src/status_im/ui/screens/events.cljs b/src/status_im/ui/screens/events.cljs index d281529e76..f06bf391a1 100644 --- a/src/status_im/ui/screens/events.cljs +++ b/src/status_im/ui/screens/events.cljs @@ -219,7 +219,10 @@ :markup data}]) "send-message" (dispatch [:send-message-from-jail {:chat-id chat_id :message data}]) - "handler-data" (dispatch [:set-handler-data chat_id data]) + "handler-result" (let [orig-params (:origParams data)] + ;; TODO(janherich): figure out and fix chat_id from event + (dispatch [:command-handler! (:chat-id orig-params) orig-params + {:result {:returned (dissoc data :origParams)}}])) (log/debug "Unknown jail signal " type)))) (register-handler-fx