From f9095a492e257aef1428a77b6c36b7e747ccafe6 Mon Sep 17 00:00:00 2001 From: andrey Date: Fri, 20 Nov 2020 10:14:23 +0100 Subject: [PATCH] [#11214] Add option for user to increase the gas payment for a pending transaction [#11215] Add option for user to cancel a pending transaction. Signed-off-by: andrey --- src/status_im/signing/core.cljs | 85 ++++++++++++++----- src/status_im/signing/core_test.cljs | 4 +- .../ui/components/bottom_panel/views.cljs | 2 +- src/status_im/ui/screens/signing/views.cljs | 26 ++++-- .../ui/screens/wallet/transactions/views.cljs | 81 ++++++++++-------- translations/en.json | 2 + 6 files changed, 133 insertions(+), 67 deletions(-) diff --git a/src/status_im/signing/core.cljs b/src/status_im/signing/core.cljs index 20826d8551..46217cf35a 100644 --- a/src/status_im/signing/core.cljs +++ b/src/status_im/signing/core.cljs @@ -19,7 +19,8 @@ [status-im.utils.utils :as utils] [status-im.wallet.prices :as prices] [status-im.wallet.core :as wallet] - [taoensso.timbre :as log])) + [taoensso.timbre :as log] + [clojure.set :as clojure.set])) (re-frame/reg-fx :signing/send-transaction-fx @@ -103,24 +104,29 @@ :cb #(re-frame/dispatch [:signing/transaction-completed % tx-obj-to-send hashed-password])}}))))) (fx/defn prepare-unconfirmed-transaction - [{:keys [db now]} hash {:keys [value gasPrice gas data to from] :as tx} symbol amount] + [{:keys [db now]} new-tx-hash {:keys [value gasPrice gas data to from hash]} symbol amount] (log/debug "[signing] prepare-unconfirmed-transaction") (let [token (tokens/symbol->token (:wallet/all-tokens db) symbol) - from (eip55/address->checksum from)] - {:db (assoc-in db [:wallet :accounts from :transactions hash] - {:timestamp (str now) - :to to - :from from - :type :pending - :hash hash - :data data - :token token - :symbol symbol - :value (if token - (money/unit->token amount (:decimals token)) - (money/to-fixed (money/bignumber value))) - :gas-price (money/to-fixed (money/bignumber gasPrice)) - :gas-limit (money/to-fixed (money/bignumber gas))})})) + from (eip55/address->checksum from) + ;;if there is a hash in the tx object that means we resending transaction + old-tx-hash hash] + {:db (-> db + ;;remove old transaction, because we replace it with the new one + (update-in [:wallet :accounts from :transactions] dissoc old-tx-hash) + (assoc-in [:wallet :accounts from :transactions new-tx-hash] + {:timestamp (str now) + :to to + :from from + :type :pending + :hash new-tx-hash + :data data + :token token + :symbol symbol + :value (if token + (money/unit->token amount (:decimals token)) + (money/to-fixed (money/bignumber value))) + :gas-price (money/to-fixed (money/bignumber gasPrice)) + :gas-limit (money/to-fixed (money/bignumber gas))}))})) (defn get-method-type [data] (cond @@ -148,15 +154,17 @@ :token token :symbol symbol})))))) -(defn parse-tx-obj [db {:keys [from to value data]}] - (merge {:from {:address from}} +(defn parse-tx-obj [db {:keys [from to value data cancel? hash]}] + (merge {:from {:address from} + :cancel? cancel? + :hash hash} (if (nil? to) {:contact {:name (i18n/label :t/new-contract)}} (let [eth-value (when value (money/bignumber value)) eth-amount (when eth-value (money/to-fixed (money/wei->ether eth-value))) token (get-transfer-token db to data)] (cond - (and eth-amount (or (not (zero? eth-amount)) (nil? data))) + (and eth-amount (or (not (.equals ^js (money/bignumber 0) ^js eth-amount)) (nil? data))) {:to to :contact (get-contact db to) :symbol :ETH @@ -468,3 +476,40 @@ :data (abi-spec/encode "transfer(address,uint256)" [to-norm amount-hex])}))})))) + +(re-frame/reg-fx + :signing/get-transaction-by-hash-fx + (fn [[hash handler]] + (json-rpc/call + {:method "eth_getTransactionByHash" + :params [hash] + :on-success handler}))) + +(fx/defn cancel-transaction-pressed + {:events [:signing.ui/cancel-transaction-pressed]} + [_ hash] + {:signing/get-transaction-by-hash-fx [hash #(re-frame/dispatch [:signing/cancel-transaction %])]}) + +(fx/defn increase-gas-pressed + {:events [:signing.ui/increase-gas-pressed]} + [_ hash] + {:signing/get-transaction-by-hash-fx [hash #(re-frame/dispatch [:signing/increase-gas %])]}) + +(fx/defn cancel-transaction + {:events [:signing/cancel-transaction]} + [cofx {:keys [from nonce hash]}] + (when (and from nonce hash) + (sign cofx {:tx-obj {:from from + :to from + :nonce nonce + :value "0x0" + :cancel? true + :hash hash}}))) + +(fx/defn increase-gas + {:events [:signing/increase-gas]} + [cofx {:keys [from nonce] :as tx}] + (when (and from nonce) + (sign cofx {:tx-obj (-> tx + (select-keys [:from :to :value :input :gas :nonce :hash]) + (clojure.set/rename-keys {:input :data}))}))) \ No newline at end of file diff --git a/src/status_im/signing/core_test.cljs b/src/status_im/signing/core_test.cljs index 5ef5b2e879..4565c2feb5 100644 --- a/src/status_im/signing/core_test.cljs +++ b/src/status_im/signing/core_test.cljs @@ -24,7 +24,7 @@ (testing "qieue is empty" (is (= (get-in sign-first [:db :signing/queue]) '()))) (testing "first tx object is parsed" - (is (= (dissoc (get-in sign-first [:db :signing/tx]) :token) + (is (= (dissoc (get-in sign-first [:db :signing/tx]) :token :hash :cancel?) (merge first-tx {:from {:address nil} :gas nil @@ -49,7 +49,7 @@ (testing "qieue is empty" (is (= (get-in first-discarded [:db :signing/queue]) '()))) (testing "second tx object is parsed" - (is (= (dissoc (get-in first-discarded [:db :signing/tx]) :token) + (is (= (dissoc (get-in first-discarded [:db :signing/tx]) :token :hash :cancel?) (merge second-tx {:from {:address nil} :gas nil diff --git a/src/status_im/ui/components/bottom_panel/views.cljs b/src/status_im/ui/components/bottom_panel/views.cljs index b43420c566..f78730378f 100644 --- a/src/status_im/ui/components/bottom_panel/views.cljs +++ b/src/status_im/ui/components/bottom_panel/views.cljs @@ -103,4 +103,4 @@ (views/defview animated-bottom-panel [val signing-view] (views/letsubs [{window-height :height} [:dimensions/window]] - [bottom-panel (when val (select-keys val [:from :contact :amount :token :approve? :message])) signing-view window-height])) + [bottom-panel (when val (select-keys val [:from :contact :amount :token :approve? :message :cancel? :hash])) signing-view window-height])) diff --git a/src/status_im/ui/screens/signing/views.cljs b/src/status_im/ui/screens/signing/views.cljs index f879894535..f9a571455b 100644 --- a/src/status_im/ui/screens/signing/views.cljs +++ b/src/status_im/ui/screens/signing/views.cljs @@ -69,7 +69,7 @@ (defn header [{:keys [in-progress?] :as sign} - {:keys [contact amount approve?]} + {:keys [contact amount approve? cancel? hash]} display-symbol fee fee-display-symbol] [react/view styles/header (when sign @@ -78,8 +78,15 @@ [icons/icon :main-icons/back]]]) [react/view {:flex 1} (if amount - [react/text {:style {:typography :title-bold}} (str (if approve? (i18n/label :t/authorize) (i18n/label :t/sending)) - " " amount " " display-symbol)] + [react/text {:style {:typography :title-bold}} (str (cond approve? + (i18n/label :t/authorize) + cancel? + (i18n/label :t/cancelling) + :else + (i18n/label :t/sending)) + (if cancel? + (str " " (utils/get-shortened-address hash)) + (str " " amount " " display-symbol)))] [react/text {:style {:typography :title-bold}} (i18n/label :t/contract-interaction)]) (if sign [react/nested-text {:style {:color colors/gray} @@ -386,7 +393,7 @@ :accessory-text network-name}])) (views/defview sheet - [{:keys [from contact amount token] :as tx}] + [{:keys [from contact amount token cancel?] :as tx}] (views/letsubs [fee [:signing/fee] sign [:signing/sign] chain [:ethereum/chain-keyword] @@ -413,9 +420,12 @@ [contact-item (i18n/label :t/from) from] [separator] [contact-item (i18n/label :t/to) contact] - [separator] - [token-item token display-symbol] - [amount-item prices wallet-currency amount amount-error display-symbol fee-display-symbol prices-loading?] + (when-not cancel? + [separator]) + (when-not cancel? + [token-item token display-symbol]) + (when-not cancel? + [amount-item prices wallet-currency amount amount-error display-symbol fee-display-symbol prices-loading?]) [separator] [fee-item prices wallet-currency fee-display-symbol fee gas-error gas-error-state prices-loading?] (when (= :gas-is-set gas-error-state) @@ -438,7 +448,7 @@ (views/letsubs [tx [:signing/tx]] [bottom-panel/animated-bottom-panel ;;we use select-keys here because we don't want to update view if other keys in map are changed - (when tx (select-keys tx [:from :contact :amount :token :approve? :message])) + (when tx (select-keys tx [:from :contact :amount :token :approve? :message :cancel? :hash])) #(if (:message %) [message-sheet] [sheet %])])) diff --git a/src/status_im/ui/screens/wallet/transactions/views.cljs b/src/status_im/ui/screens/wallet/transactions/views.cljs index a894d2b8d3..8600605cbf 100644 --- a/src/status_im/ui/screens/wallet/transactions/views.cljs +++ b/src/status_im/ui/screens/wallet/transactions/views.cljs @@ -39,42 +39,51 @@ (defn render-transaction [{:keys [label contact address contact-accessibility-label address-accessibility-label currency-text amount-text - time-formatted on-touch-fn type]}] - [list/touchable-item on-touch-fn - [react/view {:accessibility-label :transaction-item} - [list/item - (when type - [list/item-icon (transaction-type->icon (keyword type))]) - [list/item-content - [react/view {:style styles/amount-time} - [react/nested-text {:style styles/tx-amount - :ellipsize-mode "tail" - :number-of-lines 1} - [{:accessibility-label :amount-text} - amount-text] - " " - [{:accessibility-label :currency-text} - currency-text]] - [react/text {:style styles/tx-time} - time-formatted]] - [react/view {:style styles/address-row} - [react/text {:style styles/address-label} - label] - (when contact - [react/text {:style styles/address-contact - :accessibility-label contact-accessibility-label} - contact]) - [quo/text {:style styles/address-hash - :monospace true - :color :secondary - :ellipsize-mode "middle" - :number-of-lines 1 - :accessibility-label address-accessibility-label} - address]]] - [list/item-icon {:icon :main-icons/next - :style {:margin-top 10} - :icon-opts (merge styles/forward - {:accessibility-label :show-transaction-button})}]]]]) + time-formatted on-touch-fn type hash]}] + [react/view + [list/touchable-item on-touch-fn + [react/view {:accessibility-label :transaction-item} + [list/item + (when type + [list/item-icon (transaction-type->icon (keyword type))]) + [list/item-content + [react/view {:style styles/amount-time} + [react/nested-text {:style styles/tx-amount + :ellipsize-mode "tail" + :number-of-lines 1} + [{:accessibility-label :amount-text} + amount-text] + " " + [{:accessibility-label :currency-text} + currency-text]] + [react/text {:style styles/tx-time} + time-formatted]] + [react/view {:style styles/address-row} + [react/text {:style styles/address-label} + label] + (when contact + [react/text {:style styles/address-contact + :accessibility-label contact-accessibility-label} + contact]) + [quo/text {:style styles/address-hash + :monospace true + :color :secondary + :ellipsize-mode "middle" + :number-of-lines 1 + :accessibility-label address-accessibility-label} + address]]] + [list/item-icon {:icon :main-icons/next + :style {:margin-top 10} + :icon-opts (merge styles/forward + {:accessibility-label :show-transaction-button})}]]]] + (when (= type :pending) + [react/view {:flex-direction :row :padding 16 :justify-content :space-between} + [quo/button + {:on-press #(re-frame/dispatch [:signing.ui/increase-gas-pressed hash])} + (i18n/label :t/increase-gas)] + [quo/button + {:on-press #(re-frame/dispatch [:signing.ui/cancel-transaction-pressed hash])} + (i18n/label :t/cancel)]])]) (defn etherscan-link [address] (let [link @(re-frame/subscribe [:wallet/etherscan-link address])] diff --git a/translations/en.json b/translations/en.json index c3eae925f0..22a2bd1aa2 100644 --- a/translations/en.json +++ b/translations/en.json @@ -1327,5 +1327,7 @@ "ethereum-account": "Ethereum account", "ethereum-address":"Ethereum address", "default-assets": "Default ERC20 and ERC721", + "increase-gas": "Increase Gas", + "cancelling": "Cancelling", "refresh": "Refresh" }