diff --git a/src/status_im/ethereum/json_rpc.cljs b/src/status_im/ethereum/json_rpc.cljs index f2bced4c11..7927f3ba3f 100644 --- a/src/status_im/ethereum/json_rpc.cljs +++ b/src/status_im/ethereum/json_rpc.cljs @@ -175,13 +175,14 @@ (defn on-error-retry [call-method {:keys [method number-of-retries delay on-error] :as arg}] (if (pos? number-of-retries) - (fn [] + (fn [error] (let [updated-delay (if delay (min 2000 (* 2 delay)) 50)] (log/debug "[on-error-retry]" method "number-of-retries" number-of-retries - "delay" delay) + "delay" delay + "error" error) (utils/set-timeout #(call-method (-> arg (update :number-of-retries dec) (assoc :delay updated-delay))) diff --git a/src/status_im/hardwallet/card.cljs b/src/status_im/hardwallet/card.cljs index 8da7570370..960558e50e 100644 --- a/src/status_im/hardwallet/card.cljs +++ b/src/status_im/hardwallet/card.cljs @@ -402,7 +402,7 @@ (re-frame/dispatch [:hardwallet.callback/on-get-keys-error (error-object->map response)]))}))) -(defn sign [args] +(defn sign [{:keys [on-success on-failure] :as args}] (log/info "[keycard] sign" args) (keycard/sign card @@ -411,12 +411,15 @@ {:on-success (fn [response] (log/info "[keycard response succ] sign" (js->clj response :keywordize-keys true)) - (re-frame/dispatch [:hardwallet.callback/on-sign-success - response])) + (if on-success + (on-success response) + (re-frame/dispatch [:hardwallet.callback/on-sign-success response]))) :on-failure (fn [response] (log/info "[keycard response fail] sign" (error-object->map response)) - (re-frame/dispatch - [:hardwallet.callback/on-sign-error - (error-object->map response)]))}))) + (if on-failure + (on-failure response) + (re-frame/dispatch + [:hardwallet.callback/on-sign-error + (error-object->map response)])))}))) diff --git a/src/status_im/hardwallet/sign.cljs b/src/status_im/hardwallet/sign.cljs index 458cca50d3..d5dc8e3be5 100644 --- a/src/status_im/hardwallet/sign.cljs +++ b/src/status_im/hardwallet/sign.cljs @@ -31,6 +31,49 @@ (when-not keycard-match? (common/show-wrong-keycard-alert card-connected?)))))) +(fx/defn sign-message + {:events [:hardwallet/sign-message]} + [{:keys [db] :as cofx} params result] + (let [{:keys [result error]} (types/json->clj result) + on-success #(re-frame/dispatch [:hardwallet/on-sign-message-success params %]) + hash (ethereum/naked-address result) + card-connected? (get-in db [:hardwallet :card-connected?]) + pairing (common/get-pairing db) + multiaccount-keycard-instance-uid (get-in db [:multiaccount :keycard-instance-uid]) + instance-uid (get-in db [:hardwallet :application-info :instance-uid]) + keycard-match? (= multiaccount-keycard-instance-uid instance-uid) + pin (common/vector->string (get-in db [:hardwallet :pin :sign]))] + (if (and card-connected? + keycard-match?) + {:db (-> db + (assoc-in [:hardwallet :card-read-in-progress?] true) + (assoc-in [:hardwallet :pin :status] :verifying)) + :hardwallet/sign {:hash (ethereum/naked-address hash) + :pairing pairing + :pin pin + :on-success on-success}} + (fx/merge cofx + {:db (assoc-in db [:signing/sign :keycard-step] :signing)} + (common/set-on-card-connected :hardwallet/sign) + (when-not keycard-match? + (common/show-wrong-keycard-alert card-connected?)))))) + +(fx/defn on-sign-message-success + {:events [:hardwallet/on-sign-message-success]} + [{:keys [db] :as cofx} {:keys [tx-hash message-id chat-id value contract]} signature] + (fx/merge + cofx + {:dispatch + (if message-id + [:sign/send-accept-transaction-message message-id tx-hash signature] + [:sign/send-transaction-message chat-id value contract tx-hash signature]) + :db (-> db + (assoc-in [:hardwallet :pin :sign] []) + (assoc-in [:hardwallet :pin :status] nil))} + (common/clear-on-card-connected) + (common/get-application-info (common/get-pairing db) nil) + (common/hide-connection-sheet))) + (fx/defn prepare-to-sign {:events [:hardwallet/prepare-to-sign]} [{:keys [db] :as cofx}] @@ -60,16 +103,22 @@ [{:keys [db] :as cofx} signature] (log/debug "[hardwallet] sign success: " signature) (let [transaction (get-in db [:hardwallet :transaction]) - tx-obj (select-keys transaction [:from :to :value :gas :gasPrice])] + tx-obj (select-keys transaction [:from :to :value :gas :gasPrice :command? :chat-id :message-id]) + command? (:command? transaction)] (fx/merge cofx {:db (-> db - (assoc-in [:hardwallet :pin :sign] []) - (assoc-in [:hardwallet :pin :status] nil) (assoc-in [:hardwallet :hash] nil) (assoc-in [:hardwallet :transaction] nil))} - (common/clear-on-card-connected) - (common/get-application-info (common/get-pairing db) nil) - (common/hide-connection-sheet) + (when-not command? + (fn [{:keys [db] :as cofx}] + (fx/merge + cofx + {:db (-> db + (assoc-in [:hardwallet :pin :sign] []) + (assoc-in [:hardwallet :pin :status] nil))} + (common/clear-on-card-connected) + (common/get-application-info (common/get-pairing db) nil) + (common/hide-connection-sheet)))) (if transaction (send-transaction-with-signature {:transaction (types/clj->json transaction) :signature signature diff --git a/src/status_im/signing/core.cljs b/src/status_im/signing/core.cljs index 32254b4798..53d7beafbe 100644 --- a/src/status_im/signing/core.cljs +++ b/src/status_im/signing/core.cljs @@ -13,11 +13,15 @@ [status-im.native-module.core :as status] [status-im.utils.fx :as fx] [status-im.hardwallet.common :as hardwallet.common] + [status-im.hardwallet.sign :as hardwallet.sign] + [status-im.signing.keycard :as signing.keycard] [status-im.utils.hex :as utils.hex] [status-im.utils.money :as money] [status-im.utils.security :as security] [status-im.utils.types :as types] - [status-im.utils.utils :as utils])) + [status-im.utils.utils :as utils] + [taoensso.timbre :as log] + [re-frame.core :as re-frame.core])) (re-frame/reg-fx :signing/send-transaction-fx @@ -211,20 +215,22 @@ (show-sign cofx)))) (fx/defn send-transaction-message - {:events [::send-transaction-message]} + {:events [:sign/send-transaction-message]} [cofx chat-id value contract transaction-hash signature] {::json-rpc/call [{:method (json-rpc/call-ext-method (waku/enabled? cofx) "sendTransaction") :params [chat-id value contract transaction-hash - (:result (types/json->clj signature))] + (or (:result (types/json->clj signature)) + (ethereum/normalized-hex signature))] :on-success #(re-frame/dispatch [:transport/message-sent % 1])}]}) (fx/defn send-accept-request-transaction-message - {:events [::send-accept-transaction-message]} + {:events [:sign/send-accept-transaction-message]} [cofx message-id transaction-hash signature] {::json-rpc/call [{:method (json-rpc/call-ext-method (waku/enabled? cofx) "acceptRequestTransaction") :params [transaction-hash message-id - (:result (types/json->clj signature))] + (or (:result (types/json->clj signature)) + (ethereum/normalized-hex signature))] :on-success #(re-frame/dispatch [:transport/message-sent % 1])}]}) @@ -242,22 +248,38 @@ (fx/defn command-transaction-result [{:keys [db] :as cofx} transaction-hash hashed-password {:keys [message-id chat-id from] :as tx-obj}] - (let [{:keys [on-result symbol amount contract value]} (get db :signing/tx)] + (let [{:keys [on-result symbol amount contract value]} (get db :signing/tx) + data (str (get-in db [:multiaccount :public-key]) + (subs transaction-hash 2))] (fx/merge cofx - {:db (dissoc db :signing/tx :signing/in-progress? :signing/sign) - :signing.fx/sign-message - {:params {:data (str (get-in db [:multiaccount :public-key]) - (subs transaction-hash 2)) - :password hashed-password - :account from} - :on-completed - #(re-frame/dispatch - (if message-id - [::send-accept-transaction-message message-id transaction-hash %] - [::send-transaction-message - chat-id value contract transaction-hash %]))} - :signing/show-transaction-result nil} + {:db (dissoc db :signing/tx :signing/in-progress? :signing/sign)} + (if (hardwallet.common/keycard-multiaccount? db) + (signing.keycard/hash-message + {:data data + :on-completed + (fn [hash] + (re-frame.core/dispatch + [:hardwallet/sign-message + {:tx-hash transaction-hash + :message-id message-id + :chat-id chat-id + :value value + :contract contract} + hash]))}) + (fn [_] + {:signing.fx/sign-message + {:params {:data data + :password hashed-password + :account from} + :on-completed + (fn [res] + (re-frame/dispatch + (if message-id + [:sign/send-accept-transaction-message message-id transaction-hash res] + [:sign/send-transaction-message + chat-id value contract transaction-hash res])))} + :signing/show-transaction-result nil})) (prepare-unconfirmed-transaction transaction-hash tx-obj symbol amount) (check-queue) #(when on-result @@ -293,6 +315,7 @@ [cofx response tx-obj hashed-password] (let [cofx-in-progress-false (assoc-in cofx [:db :signing/sign :in-progress?] false) {:keys [result error]} (types/json->clj response)] + (log/debug "transaction-completed" error tx-obj) (if error (transaction-error cofx-in-progress-false error) (if (:command? tx-obj) @@ -317,13 +340,14 @@ (defn normalize-tx-obj [db tx] (update-in tx [:tx-obj :from] #(eip55/address->checksum (or % (ethereum/default-address db))))) -(fx/defn sign [{:keys [db] :as cofx} tx] +(fx/defn sign "Signing transaction or message, shows signing sheet tx {:tx-obj - transaction object to send https://github.com/ethereum/wiki/wiki/JavaScript-API#parameters-25 :message {:address :data :typed? } - message data to sign :on-result - re-frame event vector :on-error - re-frame event vector}" + [{:keys [db] :as cofx} tx] (fx/merge cofx {:db (update db :signing/queue conj (normalize-tx-obj db tx))} (check-queue))) diff --git a/src/status_im/signing/keycard.cljs b/src/status_im/signing/keycard.cljs index a3608d07b0..1833b1e794 100644 --- a/src/status_im/signing/keycard.cljs +++ b/src/status_im/signing/keycard.cljs @@ -4,7 +4,8 @@ [status-im.native-module.core :as status] [status-im.utils.types :as types] [status-im.ethereum.abi-spec :as abi-spec] - [status-im.ethereum.core :as ethereum])) + [status-im.ethereum.core :as ethereum] + [taoensso.timbre :as log])) (re-frame/reg-fx ::hash-transaction @@ -23,24 +24,31 @@ (defn prepare-transaction [{:keys [gas gasPrice data nonce tx-obj]}] - (let [{:keys [from to value]} tx-obj] - (cond-> {:from from - :to to - :value value - :gas (str "0x" (abi-spec/number-to-hex gas)) - :gasPrice (str "0x" (abi-spec/number-to-hex gasPrice))} + (let [{:keys [from to value chat-id message-id command?]} tx-obj] + (cond-> {:from from + :to to + :value value + :gas (str "0x" (abi-spec/number-to-hex gas)) + :gasPrice (str "0x" (abi-spec/number-to-hex gasPrice)) + :chat-id chat-id + :message-id message-id + :command? command?} data (assoc :data data) nonce (assoc :nonce nonce)))) (fx/defn hash-message - [_ {:keys [data typed?]}] + [_ {:keys [data typed? on-completed]}] (if typed? - {::hash-typed-data {:data data - :on-completed #(re-frame/dispatch [:signing.keycard.callback/hash-message-completed %])}} - {::hash-message {:message data - :on-completed #(re-frame/dispatch [:signing.keycard.callback/hash-message-completed %])}})) + {::hash-typed-data + {:data data + :on-completed + (or on-completed #(re-frame/dispatch [:signing.keycard.callback/hash-message-completed %]))}} + {::hash-message + {:message data + :on-completed + (or on-completed #(re-frame/dispatch [:signing.keycard.callback/hash-message-completed %]))}})) (fx/defn hash-message-completed {:events [:signing.keycard.callback/hash-message-completed]} @@ -51,15 +59,20 @@ (fx/defn hash-transaction [{:keys [db]}] - {::hash-transaction {:transaction (prepare-transaction (:signing/tx db)) - :on-completed #(re-frame/dispatch [:signing.keycard.callback/hash-transaction-completed %])}}) + (let [tx (prepare-transaction (:signing/tx db))] + (log/debug "hash-transaction" tx) + {::hash-transaction + {:transaction tx + :on-completed #(re-frame/dispatch + [:signing.keycard.callback/hash-transaction-completed tx %])}})) (fx/defn hash-transaction-completed {:events [:signing.keycard.callback/hash-transaction-completed]} - [{:keys [db]} result] + [{:keys [db]} original-tx result] (let [{:keys [transaction hash]} (:result (types/json->clj result))] {:db (-> db - (assoc-in [:hardwallet :transaction] transaction) + (assoc-in [:hardwallet :transaction] + (merge original-tx transaction)) (assoc-in [:hardwallet :hash] hash))})) (fx/defn sign-with-keycard diff --git a/src/status_im/ui/screens/chat/message/command.cljs b/src/status_im/ui/screens/chat/message/command.cljs index 6303a19ce6..4743d776ea 100644 --- a/src/status_im/ui/screens/chat/message/command.cljs +++ b/src/status_im/ui/screens/chat/message/command.cljs @@ -254,4 +254,4 @@ message]) #(re-frame/dispatch [::commands/decline-request-address-for-transaction - message-id])]))]]])) \ No newline at end of file + message-id])]))]]])) diff --git a/src/status_im/wallet/core.cljs b/src/status_im/wallet/core.cljs index c46bc64e25..c462126636 100644 --- a/src/status_im/wallet/core.cljs +++ b/src/status_im/wallet/core.cljs @@ -437,15 +437,14 @@ (fx/defn accept-request-transaction-button-clicked-from-command {:events [:wallet.ui/accept-request-transaction-button-clicked-from-command]} - [{:keys [db] :as cofx} chat-id {:keys [address value from id contract] :as request-parameters}] + [{:keys [db]} chat-id {:keys [value contract] :as request-parameters}] (let [identity (:current-chat-id db) all-tokens (:wallet/all-tokens db) current-network-string (:networks/current-network db) - prices (:prices db) all-networks (:networks/networks db) current-network (get all-networks current-network-string) chain (ethereum/network->chain-keyword current-network) - {:keys [symbol icon decimals] :as token} + {:keys [symbol decimals]} (if (seq contract) (get (get all-tokens chain) contract) (tokens/native-currency chain)) @@ -465,8 +464,8 @@ (fx/defn sign-transaction-button-clicked-from-request {:events [:wallet.ui/sign-transaction-button-clicked-from-request]} - [{:keys [db] :as cofx} {:keys [to amount from token gas gasPrice]}] - (let [{:keys [request-parameters]} (:wallet/prepare-transaction db) + [{:keys [db] :as cofx} {:keys [amount from token]}] + (let [{:keys [request-parameters chat-id]} (:wallet/prepare-transaction db) {:keys [symbol address]} token amount-hex (str "0x" (abi-spec/number-to-hex amount)) to-norm (:address request-parameters) @@ -480,12 +479,14 @@ {:to to-norm :from from-address :message-id (:id request-parameters) + :chat-id chat-id :command? true :value amount-hex} {:to (ethereum/normalized-hex address) :from from-address :command? true :message-id (:id request-parameters) + :chat-id chat-id :data (abi-spec/encode "transfer(address,uint256)" [to-norm amount-hex])})})))))