[#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 <motor4ik@gmail.com>
This commit is contained in:
andrey 2020-11-20 10:14:23 +01:00
parent 1f7e40cede
commit f9095a492e
No known key found for this signature in database
GPG Key ID: 89B67245FD2F0272
6 changed files with 133 additions and 67 deletions

View File

@ -19,7 +19,8 @@
[status-im.utils.utils :as utils] [status-im.utils.utils :as utils]
[status-im.wallet.prices :as prices] [status-im.wallet.prices :as prices]
[status-im.wallet.core :as wallet] [status-im.wallet.core :as wallet]
[taoensso.timbre :as log])) [taoensso.timbre :as log]
[clojure.set :as clojure.set]))
(re-frame/reg-fx (re-frame/reg-fx
:signing/send-transaction-fx :signing/send-transaction-fx
@ -103,24 +104,29 @@
:cb #(re-frame/dispatch [:signing/transaction-completed % tx-obj-to-send hashed-password])}}))))) :cb #(re-frame/dispatch [:signing/transaction-completed % tx-obj-to-send hashed-password])}})))))
(fx/defn prepare-unconfirmed-transaction (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") (log/debug "[signing] prepare-unconfirmed-transaction")
(let [token (tokens/symbol->token (:wallet/all-tokens db) symbol) (let [token (tokens/symbol->token (:wallet/all-tokens db) symbol)
from (eip55/address->checksum from)] from (eip55/address->checksum from)
{:db (assoc-in db [:wallet :accounts from :transactions hash] ;;if there is a hash in the tx object that means we resending transaction
{:timestamp (str now) old-tx-hash hash]
:to to {:db (-> db
:from from ;;remove old transaction, because we replace it with the new one
:type :pending (update-in [:wallet :accounts from :transactions] dissoc old-tx-hash)
:hash hash (assoc-in [:wallet :accounts from :transactions new-tx-hash]
:data data {:timestamp (str now)
:token token :to to
:symbol symbol :from from
:value (if token :type :pending
(money/unit->token amount (:decimals token)) :hash new-tx-hash
(money/to-fixed (money/bignumber value))) :data data
:gas-price (money/to-fixed (money/bignumber gasPrice)) :token token
:gas-limit (money/to-fixed (money/bignumber gas))})})) :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] (defn get-method-type [data]
(cond (cond
@ -148,15 +154,17 @@
:token token :token token
:symbol symbol})))))) :symbol symbol}))))))
(defn parse-tx-obj [db {:keys [from to value data]}] (defn parse-tx-obj [db {:keys [from to value data cancel? hash]}]
(merge {:from {:address from}} (merge {:from {:address from}
:cancel? cancel?
:hash hash}
(if (nil? to) (if (nil? to)
{:contact {:name (i18n/label :t/new-contract)}} {:contact {:name (i18n/label :t/new-contract)}}
(let [eth-value (when value (money/bignumber value)) (let [eth-value (when value (money/bignumber value))
eth-amount (when eth-value (money/to-fixed (money/wei->ether eth-value))) eth-amount (when eth-value (money/to-fixed (money/wei->ether eth-value)))
token (get-transfer-token db to data)] token (get-transfer-token db to data)]
(cond (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 {:to to
:contact (get-contact db to) :contact (get-contact db to)
:symbol :ETH :symbol :ETH
@ -468,3 +476,40 @@
:data (abi-spec/encode :data (abi-spec/encode
"transfer(address,uint256)" "transfer(address,uint256)"
[to-norm amount-hex])}))})))) [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}))})))

View File

@ -24,7 +24,7 @@
(testing "qieue is empty" (testing "qieue is empty"
(is (= (get-in sign-first [:db :signing/queue]) '()))) (is (= (get-in sign-first [:db :signing/queue]) '())))
(testing "first tx object is parsed" (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 (merge first-tx
{:from {:address nil} {:from {:address nil}
:gas nil :gas nil
@ -49,7 +49,7 @@
(testing "qieue is empty" (testing "qieue is empty"
(is (= (get-in first-discarded [:db :signing/queue]) '()))) (is (= (get-in first-discarded [:db :signing/queue]) '())))
(testing "second tx object is parsed" (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 (merge second-tx
{:from {:address nil} {:from {:address nil}
:gas nil :gas nil

View File

@ -103,4 +103,4 @@
(views/defview animated-bottom-panel [val signing-view] (views/defview animated-bottom-panel [val signing-view]
(views/letsubs [{window-height :height} [:dimensions/window]] (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]))

View File

@ -69,7 +69,7 @@
(defn header (defn header
[{:keys [in-progress?] :as sign} [{:keys [in-progress?] :as sign}
{:keys [contact amount approve?]} {:keys [contact amount approve? cancel? hash]}
display-symbol fee fee-display-symbol] display-symbol fee fee-display-symbol]
[react/view styles/header [react/view styles/header
(when sign (when sign
@ -78,8 +78,15 @@
[icons/icon :main-icons/back]]]) [icons/icon :main-icons/back]]])
[react/view {:flex 1} [react/view {:flex 1}
(if amount (if amount
[react/text {:style {:typography :title-bold}} (str (if approve? (i18n/label :t/authorize) (i18n/label :t/sending)) [react/text {:style {:typography :title-bold}} (str (cond approve?
" " amount " " display-symbol)] (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)]) [react/text {:style {:typography :title-bold}} (i18n/label :t/contract-interaction)])
(if sign (if sign
[react/nested-text {:style {:color colors/gray} [react/nested-text {:style {:color colors/gray}
@ -386,7 +393,7 @@
:accessory-text network-name}])) :accessory-text network-name}]))
(views/defview sheet (views/defview sheet
[{:keys [from contact amount token] :as tx}] [{:keys [from contact amount token cancel?] :as tx}]
(views/letsubs [fee [:signing/fee] (views/letsubs [fee [:signing/fee]
sign [:signing/sign] sign [:signing/sign]
chain [:ethereum/chain-keyword] chain [:ethereum/chain-keyword]
@ -413,9 +420,12 @@
[contact-item (i18n/label :t/from) from] [contact-item (i18n/label :t/from) from]
[separator] [separator]
[contact-item (i18n/label :t/to) contact] [contact-item (i18n/label :t/to) contact]
[separator] (when-not cancel?
[token-item token display-symbol] [separator])
[amount-item prices wallet-currency amount amount-error display-symbol fee-display-symbol prices-loading?] (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] [separator]
[fee-item prices wallet-currency fee-display-symbol fee gas-error gas-error-state prices-loading?] [fee-item prices wallet-currency fee-display-symbol fee gas-error gas-error-state prices-loading?]
(when (= :gas-is-set gas-error-state) (when (= :gas-is-set gas-error-state)
@ -438,7 +448,7 @@
(views/letsubs [tx [:signing/tx]] (views/letsubs [tx [:signing/tx]]
[bottom-panel/animated-bottom-panel [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 ;;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 %) #(if (:message %)
[message-sheet] [message-sheet]
[sheet %])])) [sheet %])]))

View File

@ -39,42 +39,51 @@
(defn render-transaction (defn render-transaction
[{:keys [label contact address contact-accessibility-label [{:keys [label contact address contact-accessibility-label
address-accessibility-label currency-text amount-text address-accessibility-label currency-text amount-text
time-formatted on-touch-fn type]}] time-formatted on-touch-fn type hash]}]
[list/touchable-item on-touch-fn [react/view
[react/view {:accessibility-label :transaction-item} [list/touchable-item on-touch-fn
[list/item [react/view {:accessibility-label :transaction-item}
(when type [list/item
[list/item-icon (transaction-type->icon (keyword type))]) (when type
[list/item-content [list/item-icon (transaction-type->icon (keyword type))])
[react/view {:style styles/amount-time} [list/item-content
[react/nested-text {:style styles/tx-amount [react/view {:style styles/amount-time}
:ellipsize-mode "tail" [react/nested-text {:style styles/tx-amount
:number-of-lines 1} :ellipsize-mode "tail"
[{:accessibility-label :amount-text} :number-of-lines 1}
amount-text] [{:accessibility-label :amount-text}
" " amount-text]
[{:accessibility-label :currency-text} " "
currency-text]] [{:accessibility-label :currency-text}
[react/text {:style styles/tx-time} currency-text]]
time-formatted]] [react/text {:style styles/tx-time}
[react/view {:style styles/address-row} time-formatted]]
[react/text {:style styles/address-label} [react/view {:style styles/address-row}
label] [react/text {:style styles/address-label}
(when contact label]
[react/text {:style styles/address-contact (when contact
:accessibility-label contact-accessibility-label} [react/text {:style styles/address-contact
contact]) :accessibility-label contact-accessibility-label}
[quo/text {:style styles/address-hash contact])
:monospace true [quo/text {:style styles/address-hash
:color :secondary :monospace true
:ellipsize-mode "middle" :color :secondary
:number-of-lines 1 :ellipsize-mode "middle"
:accessibility-label address-accessibility-label} :number-of-lines 1
address]]] :accessibility-label address-accessibility-label}
[list/item-icon {:icon :main-icons/next address]]]
:style {:margin-top 10} [list/item-icon {:icon :main-icons/next
:icon-opts (merge styles/forward :style {:margin-top 10}
{:accessibility-label :show-transaction-button})}]]]]) :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] (defn etherscan-link [address]
(let [link @(re-frame/subscribe [:wallet/etherscan-link address])] (let [link @(re-frame/subscribe [:wallet/etherscan-link address])]

View File

@ -1327,5 +1327,7 @@
"ethereum-account": "Ethereum account", "ethereum-account": "Ethereum account",
"ethereum-address":"Ethereum address", "ethereum-address":"Ethereum address",
"default-assets": "Default ERC20 and ERC721", "default-assets": "Default ERC20 and ERC721",
"increase-gas": "Increase Gas",
"cancelling": "Cancelling",
"refresh": "Refresh" "refresh": "Refresh"
} }