Revert "Revert "[#7133] sign tx with keycard""

This reverts commit 4ccb1ea52d.

Signed-off-by: Dmitry Novotochinov <dmitry.novot@gmail.com>
This commit is contained in:
Dmitry Novotochinov 2019-04-03 11:46:53 +03:00
parent f8674c0ee1
commit 4decedf5f6
No known key found for this signature in database
GPG Key ID: 43D1DAF5AD39C927
20 changed files with 437 additions and 121 deletions

View File

@ -54,7 +54,7 @@
"react-native-safe-area-view": "0.9.0",
"react-native-securerandom": "git+https://github.com/status-im/react-native-securerandom.git#0.1.1-2",
"react-native-splash-screen": "3.1.1",
"react-native-status-keycard": "git+https://github.com/status-im/react-native-status-keycard.git#v2.3.10",
"react-native-status-keycard": "git+https://github.com/status-im/react-native-status-keycard.git#v2.4.0",
"react-native-svg": "^9.2.4",
"react-native-svg-transformer": "^0.12.1",
"react-native-tcp": "git+https://github.com/status-im/react-native-tcp.git#v3.3.0-1-status",

View File

@ -5355,9 +5355,9 @@ react-native-splash-screen@3.1.1:
resolved "https://registry.yarnpkg.com/react-native-splash-screen/-/react-native-splash-screen-3.1.1.tgz#1a4e46c9fdce53ff52af2a2cb4181788c4e30b30"
integrity sha512-PU2YocOSGbLjL9Vgcq/cwMNuHHKNjjuPpa1IPMuWo+6EB/fSZ5VOmxSa7+eucQe3631s3NhGuk3eHKahU03a4Q==
"react-native-status-keycard@git+https://github.com/status-im/react-native-status-keycard.git#v2.3.10":
version "2.3.10"
resolved "git+https://github.com/status-im/react-native-status-keycard.git#a6da0a7889fdbc8cdf61771cf1b989c5cfb14b08"
"react-native-status-keycard@git+https://github.com/status-im/react-native-status-keycard.git#v2.4.0":
version "2.4.0"
resolved "git+https://github.com/status-im/react-native-status-keycard.git#b9a66144b3942e40ffb30cb27fa01202b0d11061"
react-native-svg-transformer@^0.12.1:
version "0.12.1"

View File

@ -700,6 +700,45 @@ class StatusModule extends ReactContextBaseJavaModule implements LifecycleEventL
StatusThreadPoolExecutor.getInstance().execute(r);
}
@ReactMethod
public void hashMessage(final String message, final Callback callback) {
Log.d(TAG, "hashMessage");
if (!checkAvailability()) {
callback.invoke(false);
return;
}
Runnable r = new Runnable() {
@Override
public void run() {
String res = Statusgo.hashMessage(message);
callback.invoke(res);
}
};
StatusThreadPoolExecutor.getInstance().execute(r);
}
@ReactMethod
public void hashTypedData(final String data, final Callback callback) {
Log.d(TAG, "hashTypedData");
if (!checkAvailability()) {
callback.invoke(false);
return;
}
Runnable r = new Runnable() {
@Override
public void run() {
String res = Statusgo.hashTypedData(data);
callback.invoke(res);
}
};
StatusThreadPoolExecutor.getInstance().execute(r);
}
@ReactMethod
public void sendTransactionWithSignature(final String txArgsJSON, final String signature, final Callback callback) {
Log.d(TAG, "sendTransactionWithSignature");

View File

@ -956,7 +956,7 @@
(handlers/register-handler-fx
:hardwallet/get-application-info
(fn [cofx _]
(hardwallet/get-application-info cofx nil)))
(hardwallet/get-application-info cofx nil nil)))
(handlers/register-handler-fx
:hardwallet.callback/on-get-application-info-success
@ -1096,6 +1096,11 @@
(fn [cofx [_ data]]
(hardwallet/on-get-keys-success cofx data)))
(handlers/register-handler-fx
:hardwallet.callback/on-sign-success
(fn [cofx [_ data]]
(hardwallet/on-sign-success cofx data)))
(handlers/register-handler-fx
:hardwallet/auto-login
(fn [cofx _]
@ -1116,6 +1121,11 @@
(fn [cofx [_ error]]
(hardwallet/on-get-keys-error cofx error)))
(handlers/register-handler-fx
:hardwallet.callback/on-sign-error
(fn [cofx [_ error]]
(hardwallet/on-sign-error cofx error)))
(handlers/register-handler-fx
:hardwallet.ui/status-hardwallet-option-pressed
(fn [cofx _]
@ -1250,6 +1260,11 @@
(fn [cofx [_ number step]]
(hardwallet/update-pin cofx number step)))
(handlers/register-handler-fx
:hardwallet.ui/navigate-back-button-clicked
(fn [cofx _]
(hardwallet/navigate-back-button-clicked cofx)))
(handlers/register-handler-fx
:hardwallet/process-pin-input
(fn [cofx _]
@ -1343,6 +1358,11 @@
(fn [cofx _]
(hardwallet/navigate-to-reset-card-screen cofx)))
(handlers/register-handler-fx
:hardwallet/sign
(fn [cofx _]
(hardwallet/sign cofx)))
;; browser module
(handlers/register-handler-fx

View File

@ -154,3 +154,11 @@
(getKeys pairing pin)
(then #(re-frame/dispatch [:hardwallet.callback/on-get-keys-success %]))
(catch #(re-frame/dispatch [:hardwallet.callback/on-get-keys-error (error-object->map %)]))))
(defn sign
[{:keys [pairing pin hash]}]
(when (and pairing pin hash)
(.. keycard
(sign pairing pin hash)
(then #(re-frame/dispatch [:hardwallet.callback/on-sign-success %]))
(catch #(re-frame/dispatch [:hardwallet.callback/on-sign-error (error-object->map %)])))))

View File

@ -7,13 +7,16 @@
[status-im.utils.platform :as platform]
[taoensso.timbre :as log]
[status-im.i18n :as i18n]
[status-im.utils.types :as types]
[status-im.accounts.create.core :as accounts.create]
[status-im.node.core :as node]
[status-im.utils.datetime :as utils.datetime]
[status-im.data-store.accounts :as accounts-store]
[status-im.utils.ethereum.core :as ethereum]
[clojure.string :as string]
[status-im.accounts.login.core :as accounts.login]
[status-im.accounts.recover.core :as accounts.recover]))
[status-im.accounts.recover.core :as accounts.recover]
[status-im.models.wallet :as models.wallet]))
(def default-pin "000000")
@ -27,7 +30,7 @@
(defn get-pairing
([db]
(get-pairing db nil))
(get-pairing db (get-in db [:hardwallet :application-info :instance-uid])))
([db instance-uid]
(or
(get-in db [:account/account :keycard-pairing])
@ -36,6 +39,21 @@
(:keycard-pairing
(find-account-by-keycard-instance-uid db instance-uid))))))
(fx/defn navigate-back-button-clicked
[{:keys [db] :as cofx}]
(let [screen-before (second (get db :navigation-stack))
navigate-to-browser? (contains? #{:wallet-sign-message-modal
:wallet-send-transaction-modal
:wallet-send-modal-stack} screen-before)]
(if navigate-to-browser?
(fx/merge cofx
{:db (assoc-in db [:hardwallet :on-card-connected] nil)}
(models.wallet/discard-transaction)
(navigation/navigate-to-cofx :browser nil))
(fx/merge cofx
{:db (assoc-in db [:hardwallet :on-card-connected] nil)}
(navigation/navigate-back)))))
(fx/defn remove-pairing-from-account
[{:keys [db]} {:keys [remove-instance-uid?]}]
(let [account (cond-> (:account/account db)
@ -188,6 +206,7 @@
(defn enter-pin-screen-did-load
[{:keys [db]}]
{:db (-> db
(assoc-in [:hardwallet :pin :sign] [])
(assoc-in [:hardwallet :pin :login] [])
(assoc-in [:hardwallet :pin :current] []))})
@ -274,7 +293,8 @@
(let [info' (js->clj info :keywordize-keys true)
{:keys [pin-retry-counter puk-retry-counter instance-uid]} info'
connect-screen? (= (:view-id db) :hardwallet-connect)
card-state (get-in db [:hardwallet :card-state])
{:keys [card-state on-card-read]} (:hardwallet db)
on-success' (or on-success on-card-read)
accounts-screen? (= :accounts (:view-id db))
auto-login? (and accounts-screen?
(not= on-success :hardwallet/auto-login))
@ -295,9 +315,10 @@
instance-uid)
(check-card-state))
(if (zero? puk-retry-counter)
(navigation/navigate-to-cofx :keycard-settings nil)
(when on-success
(dispatch-event on-success))))))
{:utils/show-popup {:title (i18n/label :t/error)
:content (i18n/label :t/keycard-blocked)}}
(when on-success'
(dispatch-event on-success'))))))
(fx/defn on-get-application-info-error
[{:keys [db] :as cofx} error]
@ -570,12 +591,13 @@
:enter-step :puk
:puk []})}))
(fx/defn get-application-info
[{:keys [db]} pairing]
[{:keys [db]} pairing on-card-read]
(let [instance-uid (get-in db [:hardwallet :application-info :instance-uid])
pairing' (or pairing
(when instance-uid
(get-pairing db instance-uid)))]
{:hardwallet/get-application-info {:pairing pairing'}}))
{:hardwallet/get-application-info {:pairing pairing'
:on-success on-card-read}}))
(fx/defn on-verify-pin-success
[{:keys [db] :as cofx}]
@ -586,7 +608,7 @@
(update-in [:hardwallet :pin] merge {:status nil
:error-label nil}))}
(when-not (contains? #{:hardwallet/unpair :hardwallet/unpair-and-delete} on-verified)
(get-application-info pairing))
(get-application-info pairing nil))
(when on-verified
(dispatch-on-verified-event on-verified)))))
@ -613,7 +635,7 @@
:error-label nil}))
:utils/show-popup {:title ""
:content (i18n/label :t/pin-changed {:pin pin})}}
(navigation/navigate-to-cofx :keycard-settings nil))))
(navigation/navigate-back))))
(fx/defn on-change-pin-error
[{:keys [db]} error]
@ -664,7 +686,8 @@
(defn- unblock-pin
[{:keys [db] :as fx}]
(let [puk (vector->string (get-in fx [:db :hardwallet :pin :puk]))
pairing (get-pairing db)]
instance-uid (get-in db [:hardwallet :application-info :instance-uid])
pairing (get-pairing db instance-uid)]
{:db (assoc-in db [:hardwallet :pin :status] :verifying)
:hardwallet/unblock-pin {:puk puk
:new-pin default-pin
@ -709,8 +732,26 @@
(assoc-in [:hardwallet :on-card-read] :hardwallet/login-with-keycard))}
(navigation/navigate-to-cofx :hardwallet-connect nil)))))
(fx/defn sign
[{:keys [db] :as cofx}]
(let [card-connected? (get-in db [:hardwallet :card-connected?])
pairing (get-pairing db)
hash (get-in db [:hardwallet :hash])
pin (vector->string (get-in db [:hardwallet :pin :sign]))]
(if card-connected?
{: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}}
(fx/merge cofx
{:db (assoc-in db [:hardwallet :on-card-connected] :hardwallet/sign)}
(navigation/navigate-to-cofx :hardwallet-connect nil)))))
; PIN enter steps:
; login - PIN is used to login
; sign - PIN for transaction sign
; current - current PIN to perform actions which require PIN auth
; original - new PIN when user changes it or creates new one
; confirmation - confirmation for new PIN
@ -738,6 +779,10 @@
(= pin-code-length numbers-entered))
(verify-pin)
(and (= enter-step :sign)
(= pin-code-length numbers-entered))
(sign)
(and (= enter-step :puk)
(= puk-code-length numbers-entered))
(unblock-pin)
@ -798,11 +843,11 @@
:else (get-in db [:hardwallet :on-card-read]))
pairing (get-pairing db instance-uid)]
(fx/merge cofx
{:db (-> db
(assoc-in [:hardwallet :card-connected?] true)
(assoc-in [:hardwallet :card-read-in-progress?] (boolean on-card-read)))
:hardwallet/get-application-info {:pairing pairing
:on-success on-card-read}}
{:db (-> db
(assoc-in [:hardwallet :card-connected?] true)
(assoc-in [:hardwallet :card-read-in-progress?] (boolean on-card-read)))}
(when (not= on-card-connected :hardwallet/sign)
(get-application-info pairing on-card-read))
(when (and on-card-connected
(not login?))
(dispatch-event on-card-connected))
@ -1057,30 +1102,81 @@
encryption-public-key]} (js->clj data :keywordize-keys true)
whisper-public-key' (str "0x" whisper-public-key)
{:keys [photo-path name]} (get-in db [:accounts/accounts wallet-address])
password encryption-public-key]
password encryption-public-key
instance-uid (get-in db [:hardwallet :application-info :instance-uid])]
(fx/merge cofx
{:db (-> db
(assoc-in [:hardwallet :pin :status] nil)
(assoc-in [:hardwallet :whisper-public-key] whisper-public-key')
(assoc-in [:hardwallet :whisper-private-key] whisper-private-key)
(assoc-in [:hardwallet :wallet-address] wallet-address)
(assoc-in [:hardwallet :encryption-public-key] encryption-public-key)
(update :accounts/login assoc
:password password
:address wallet-address
:photo-path photo-path
:name name))}
{:db (-> db
(assoc-in [:hardwallet :pin :status] nil)
(assoc-in [:hardwallet :pin :login] [])
(assoc-in [:hardwallet :whisper-public-key] whisper-public-key')
(assoc-in [:hardwallet :whisper-private-key] whisper-private-key)
(assoc-in [:hardwallet :wallet-address] wallet-address)
(assoc-in [:hardwallet :encryption-public-key] encryption-public-key)
(update :accounts/login assoc
:password password
:address wallet-address
:photo-path photo-path
:name name))
:hardwallet/get-application-info {:pairing (get-pairing db instance-uid)}}
(accounts.login/user-login true))))
(fx/defn on-get-keys-error
[{:keys [db] :as cofx} error]
(log/debug "[hardwallet] get keys error: " error)
(let [tag-was-lost? (= "Tag was lost." (:error error))]
(let [tag-was-lost? (= "Tag was lost." (:error error))
instance-uid (get-in db [:hardwallet :application-info :instance-uid])]
(if tag-was-lost?
{:utils/show-popup {:title (i18n/label :t/error)
:content (i18n/label :t/tag-was-lost)}}
(fx/merge cofx
{:hardwallet/get-application-info {:pairing (get-pairing db)}
{:hardwallet/get-application-info {:pairing (get-pairing db instance-uid)}
:db (update-in db [:hardwallet :pin] merge {:status :error
:login []
:error-label :t/pin-mismatch})}
(navigation/navigate-to-cofx :enter-pin nil)))))
(fx/defn send-transaction-with-signature
[_ data]
{:send-transaction-with-signature data})
(fx/defn sign-message-completed
[{:keys [db]} signature]
(let [screen-params (get-in db [:navigation/screen-params :wallet-sign-message-modal])
signature' (-> signature
; add 27 to last byte
; https://github.com/ethereum/go-ethereum/blob/master/internal/ethapi/api.go#L431
(clojure.string/replace-first #"00$", "1b")
(clojure.string/replace-first #"01$", "1c")
(ethereum/normalized-address))]
{:dispatch
[:status-im.ui.screens.wallet.send.events/sign-message-completed
screen-params
{:result signature'}]}))
(fx/defn on-sign-success
[{:keys [db] :as cofx} signature]
(log/debug "[hardwallet] sign success: " signature)
(let [transaction (get-in db [:hardwallet :transaction])]
(fx/merge cofx
{:db (-> db
(assoc-in [:hardwallet :pin :sign] [])
(assoc-in [:hardwallet :pin :status] nil)
(assoc-in [:hardwallet :on-card-connected] nil)
(assoc-in [:hardwallet :hash] nil)
(assoc-in [:hardwallet :transaction] nil))}
(get-application-info (get-pairing db) nil)
(if transaction
(send-transaction-with-signature {:transaction (types/clj->json transaction)
:signature signature
:on-completed #(re-frame/dispatch [:status-im.ui.screens.wallet.send.events/transaction-completed (types/json->clj %)])})
(sign-message-completed signature)))))
(fx/defn on-sign-error
[{:keys [db] :as cofx} error]
(log/debug "[hardwallet] sign error: " error)
(fx/merge cofx
{:db (update-in db [:hardwallet :pin] merge {:status :error
:sign []
:error-label :t/pin-mismatch})}
(navigation/navigate-to-cofx :enter-pin nil)
(get-application-info (get-pairing db) nil)))

View File

@ -77,6 +77,15 @@
:hardwallet/get-keys
card/get-keys)
(re-frame/reg-fx
:hardwallet/sign
card/sign)
(re-frame/reg-fx
:hardwallet/login-with-keycard
statusgo/login-with-keycard)
(re-frame/reg-fx
:send-transaction-with-signature
(fn [{:keys [transaction signature on-completed]}]
(statusgo/send-transaction-with-signature transaction signature on-completed)))

View File

@ -119,7 +119,7 @@
:error message}
:webview webview-bridge}))
(defn dapp-complete-transaction [id result method message-id webview]
(defn dapp-complete-transaction [id result method message-id webview keycard?]
(cond-> {:browser/send-to-bridge {:message {:type constants/web3-send-async-callback
:messageId message-id
:result {:jsonrpc "2.0"
@ -129,7 +129,7 @@
:dispatch [:navigate-back]}
(constants/web3-sign-message? method)
(assoc :dispatch [:navigate-back])
(assoc :dispatch (if keycard? [:navigate-to :browser] [:navigate-back]))
(= method constants/web3-send-transaction)
(assoc :dispatch [:navigate-to-clean :wallet-transaction-sent-modal])))

View File

@ -58,6 +58,12 @@
(defn hash-transaction [rpcParams callback]
(native-module/hash-transaction rpcParams callback))
(defn hash-message [message callback]
(native-module/hash-message message callback))
(defn hash-typed-data [data callback]
(native-module/hash-typed-data data callback))
(defn send-transaction-with-signature [rpcParams sig callback]
(native-module/send-transaction-with-signature rpcParams sig callback))

View File

@ -98,6 +98,14 @@
(when (and @node-started status)
(.hashTransaction status rpcParams callback)))
(defn hash-message [message callback]
(when (and @node-started status)
(.hashMessage status message callback)))
(defn hash-typed-data [data callback]
(when (and @node-started status)
(.hashTypedData status data callback)))
(defn sign-typed-data [data password callback]
(when (and @node-started status)
(.signTypedData status data password callback)))

View File

@ -40,7 +40,8 @@
(i18n/label :t/go-to-settings)]]])
(defview hardwallet-connect []
(letsubs [nfc-enabled? [:hardwallet/nfc-enabled?]]
(letsubs [nfc-enabled? [:hardwallet/nfc-enabled?]
setup-step [:hardwallet-setup-step]]
[react/view styles/container
[status-bar/status-bar]
[react/view {:flex 1
@ -53,10 +54,11 @@
(if nfc-enabled?
[nfc-enabled]
[nfc-disabled])]
[react/view styles/bottom-container
[react/touchable-highlight {:on-press #(.openURL react/linking "https://hardwallet.status.im")}
[react/view styles/product-info-container
[react/text {:style styles/product-info-text}
(i18n/label :t/product-information)]
[vector-icons/icon :main-icons/link {:color colors/blue
:container-style styles/external-link-icon}]]]]]]))
(if (= setup-step :begin)
[react/view styles/bottom-container
[react/touchable-highlight {:on-press #(.openURL react/linking "https://hardwallet.status.im")}
[react/view styles/product-info-container
[react/text {:style styles/product-info-text}
(i18n/label :t/product-information)]
[vector-icons/icon :main-icons/link {:color colors/blue
:container-style styles/external-link-icon}]]]])]]))

View File

@ -9,7 +9,8 @@
[status-im.ui.screens.hardwallet.components :as components]
[status-im.ui.components.toolbar.view :as toolbar]
[status-im.ui.components.status-bar.view :as status-bar]
[status-im.ui.components.toolbar.actions :as actions]))
[status-im.ui.components.toolbar.actions :as actions]
[status-im.ui.components.toolbar.actions :as toolbar.actions]))
(defn numpad-button [n step enabled?]
[react/touchable-highlight
@ -31,8 +32,7 @@
[numpad-row [4 5 6] step enabled?]
[numpad-row [7 8 9] step enabled?]
[react/view styles/numpad-row-container
[react/view styles/numpad-empty-button
[react/text {:style styles/numpad-empty-button-text}]]
[react/view styles/numpad-empty-button]
[numpad-button 0 step enabled?]
[react/touchable-highlight
{:on-press #(when enabled?
@ -125,7 +125,12 @@
[react/view {:flex 1
:background-color colors/white}
[status-bar/status-bar]
[toolbar/toolbar nil toolbar/default-nav-back nil]
[toolbar/toolbar
nil
[toolbar/nav-button (assoc toolbar.actions/default-back
:handler
#(re-frame/dispatch [:hardwallet.ui/navigate-back-button-clicked]))]
nil]
(if (zero? pin-retry-counter)
[pin-view {:pin pin
:retry-counter (when (< puk-retry-counter puk-retries) puk-retry-counter)
@ -144,6 +149,7 @@
:t/current-pin)
:description-label (case step
:current :t/current-pin-description
:sign :t/current-pin-description
:login :t/login-pin-description
:t/new-pin-description)
:step step

View File

@ -33,3 +33,9 @@
:keycard-reset-card-disabled?
(fn [db]
(get-in db [:hardwallet :reset-card :disabled?] false)))
(re-frame/reg-sub
:keycard-account?
(fn [db]
(boolean
(get-in db [:account/account :keycard-instance-uid]))))

View File

@ -4,13 +4,17 @@
[{:name :wallet-send-modal-stack
:screens [:wallet-send-transaction-modal
:wallet-transaction-sent-modal
:wallet-transaction-fee]
:wallet-transaction-fee
:hardwallet-connect
:enter-pin]
:config {:initialRouteName :wallet-send-transaction-modal}}
{:name :wallet-send-modal-stack-with-onboarding
:screens [:wallet-onboarding-setup-modal
:wallet-send-transaction-modal
:wallet-transaction-sent-modal
:wallet-transaction-fee]
:wallet-transaction-fee
:hardwallet-connect
:enter-pin]
:config {:initialRouteName :wallet-onboarding-setup-modal}}
:chat-modal
:show-extension-modal

View File

@ -11,6 +11,8 @@
:screens [:wallet-send-transaction
:recent-recipients
:wallet-transaction-sent
:enter-pin
:hardwallet-connect
:recipient-qr-code
:wallet-send-assets]}
{:name :request-transaction-stack

View File

@ -20,7 +20,8 @@
[status-im.utils.types :as types]
[status-im.utils.utils :as utils]
[status-im.utils.config :as config]
[status-im.transport.utils :as transport.utils]))
[status-im.transport.utils :as transport.utils]
[status-im.hardwallet.core :as hardwallet]))
;;;; FX
@ -77,27 +78,6 @@
#(re-frame/dispatch [::transaction-completed (types/json->clj %)])
password]}))))
;; SIGN MESSAGE
(handlers/register-handler-fx
:wallet/sign-message
(fn [_ [_ typed? screen-params password-error-cb]]
(let [{:keys [data from password]} screen-params]
(if typed?
{::sign-typed-data {:data data
:password password
:account from
:on-completed #(re-frame/dispatch [::sign-message-completed
screen-params
(types/json->clj %)
password-error-cb])}}
{::sign-message {:params {:data data
:password (security/safe-unmask-data password)
:account from}
:on-completed #(re-frame/dispatch [::sign-message-completed
screen-params
(types/json->clj %)
password-error-cb])}}))))
;; SEND TRANSACTION CALLBACK
(handlers/register-handler-fx
::transaction-completed
@ -139,6 +119,20 @@
(if on-result
{:dispatch (conj on-result id result method)})))))
(handlers/register-handler-fx
::hash-message-completed
(fn [{:keys [db] :as cofx} [_ {:keys [result error]}]]
(let [db' (assoc-in db [:wallet :send-transaction :in-progress?] false)]
(if error
;; ERROR
(models.wallet/handle-transaction-error (assoc cofx :db db') error)
;; RESULT
(fx/merge cofx
{:db (-> db
(assoc-in [:hardwallet :pin :enter-step] :sign)
(assoc-in [:hardwallet :hash] result))}
(navigation/navigate-to-cofx :enter-pin nil))))))
;; DISCARD TRANSACTION
(handlers/register-handler-fx
:wallet/discard-transaction
@ -148,8 +142,9 @@
(handlers/register-handler-fx
:wallet.dapp/transaction-on-result
(fn [{db :db} [_ message-id id result method]]
(let [webview (:webview-bridge db)]
(models.wallet/dapp-complete-transaction (int id) result method message-id webview))))
(let [webview (:webview-bridge db)
keycard? (boolean (get-in db [:account/account :keycard-instance-uid]))]
(models.wallet/dapp-complete-transaction (int id) result method message-id webview keycard?))))
(handlers/register-handler-fx
:wallet.dapp/transaction-on-error
@ -165,6 +160,7 @@
(let [{:keys [send-transaction transactions-queue]} (:wallet db)
{:keys [payload message-id] :as queued-transaction} (last transactions-queue)
{:keys [method params id]} payload
keycard? (boolean (get-in db [:account/account :keycard-instance-uid]))
db' (update-in db [:wallet :transactions-queue] drop-last)]
(when (and (not (contains? #{:wallet-transaction-sent
:wallet-transaction-sent-modal}
@ -182,14 +178,18 @@
(let [typed? (not= constants/web3-personal-sign method)
[address data] (models.wallet/normalize-sign-message-params params)]
(if (and address data)
(let [screen-params {:id (str (or id message-id))
:from address
:data data
:typed? typed?
:decoded-data (if typed? (types/json->clj data) (transport.utils/to-utf8 data))
:on-result [:wallet.dapp/transaction-on-result message-id]
:on-error [:wallet.dapp/transaction-on-error message-id]
:method method}]
(let [signing-phrase (-> (get-in db [:account/account :signing-phrase])
(clojure.string/replace-all #" " " "))
screen-params {:id (str (or id message-id))
:from address
:data data
:typed? typed?
:decoded-data (if typed? (types/json->clj data) (transport.utils/to-utf8 data))
:on-result [:wallet.dapp/transaction-on-result message-id]
:on-error [:wallet.dapp/transaction-on-error message-id]
:method method
:signing-phrase signing-phrase
:keycard? keycard?}]
(navigation/navigate-to-cofx {:db db'} :wallet-sign-message-modal screen-params))
{:db db'})))))))
@ -205,7 +205,7 @@
#(when send-command?
(commands-sending/send % chat-id send-command? params))
(navigation/navigate-to-clean
(if (= (:view-id db) :wallet-send-transaction)
(if (contains? #{:wallet-send-transaction :enter-pin :hardwallet-connect} (:view-id db))
:wallet-transaction-sent
:wallet-transaction-sent-modal)
{})))))
@ -314,3 +314,74 @@
{:dispatch-later [{:ms 400 :dispatch [:check-dapps-transactions-queue]}]}
(navigation/navigate-back))))
(re-frame/reg-fx
::hash-transaction
(fn [{:keys [transaction all-tokens symbol chain on-completed]}]
(status/hash-transaction (types/clj->json transaction) on-completed)))
(re-frame/reg-fx
::hash-message
(fn [{:keys [message on-completed]}]
(status/hash-message message on-completed)))
(re-frame/reg-fx
::hash-typed-data
(fn [{:keys [data on-completed]}]
(status/hash-typed-data data on-completed)))
(defn send-keycard-transaction
[{{:keys [chain] :as db} :db}]
(let [{:keys [symbol] :as transaction} (get-in db [:wallet :send-transaction])
all-tokens (:wallet/all-tokens db)
from (get-in db [:account/account :address])]
{::hash-transaction {:transaction (models.wallet/prepare-send-transaction from transaction)
:all-tokens all-tokens
:symbol symbol
:chain chain
:on-completed #(re-frame/dispatch [:wallet.callback/hash-transaction-completed %])}}))
(handlers/register-handler-fx
:wallet.callback/hash-transaction-completed
(fn [{:keys [db] :as cofx} [_ result]]
(let [{:keys [transaction hash]} (:result (types/json->clj result))]
(fx/merge cofx
{:db (-> db
(assoc-in [:hardwallet :pin :enter-step] :sign)
(assoc-in [:hardwallet :transaction] transaction)
(assoc-in [:hardwallet :hash] hash))}
(navigation/navigate-to-clean :enter-pin nil)))))
(handlers/register-handler-fx
:wallet.ui/sign-transaction-button-clicked
(fn [{:keys [db] :as cofx} _]
(let [keycard-account? (boolean (get-in db [:account/account :keycard-instance-uid]))]
(if keycard-account?
(send-keycard-transaction cofx)
{:db (assoc-in db [:wallet :send-transaction :show-password-input?] true)}))))
(handlers/register-handler-fx
:wallet.ui/sign-message-button-clicked
(fn [{:keys [db]} [_ typed? screen-params password-error-cb]]
(let [{:keys [data from password]} screen-params
keycard-account? (boolean (get-in db [:account/account :keycard-instance-uid]))]
(if keycard-account?
(if typed?
{::hash-typed-data {:data data
:on-completed #(re-frame/dispatch [::hash-message-completed (types/json->clj %)])}}
{::hash-message {:message (ethereum/naked-address data)
:on-completed #(re-frame/dispatch [::hash-message-completed (types/json->clj %)])}})
(if typed?
{::sign-typed-data {:data data
:password password
:account from
:on-completed #(re-frame/dispatch [::sign-message-completed
screen-params
(types/json->clj %)
password-error-cb])}}
{::sign-message {:params {:data data
:password (security/safe-unmask-data password)
:account from}
:on-completed #(re-frame/dispatch [::sign-message-completed
screen-params
(types/json->clj %)
password-error-cb])}})))))

View File

@ -89,3 +89,9 @@
(models.wallet/add-max-fee)
(check-sufficient-funds balance symbol amount)
(check-sufficient-gas balance symbol amount))))
(re-frame/reg-sub
:wallet.send/signing-phrase-with-padding
:<- [:account/account]
(fn [{:keys [signing-phrase]}]
(clojure.string/replace-all signing-phrase #" " " ")))

View File

@ -41,8 +41,8 @@
(defn- advanced-cartouche [native-currency {:keys [max-fee gas gas-price]}]
[react/view
[wallet.components/cartouche {:on-press #(do (re-frame/dispatch [:wallet.send/clear-gas])
(re-frame/dispatch [:navigate-to :wallet-transaction-fee]))}
[wallet.components/cartouche {:on-press #(do (re-frame/dispatch [:wallet.send/clear-gas])
(re-frame/dispatch [:navigate-to :wallet-transaction-fee]))}
(i18n/label :t/wallet-transaction-fee)
[react/view {:style styles/advanced-options-text-wrapper
:accessibility-label :transaction-fee-button}
@ -67,11 +67,11 @@
[advanced-cartouche native-currency transaction])])
(defview password-input-panel [message-label spinning?]
(letsubs [account [:account/account]
(letsubs [account [:account/account]
wrong-password? [:wallet.send/wrong-password?]
signing-phrase (:signing-phrase @account)
bottom-value (animation/create-value -250)
opacity-value (animation/create-value 0)]
signing-phrase (:signing-phrase @account)
bottom-value (animation/create-value -250)
opacity-value (animation/create-value 0)]
{:component-did-mount #(send.animations/animate-sign-panel opacity-value bottom-value)}
[react/animated-view {:style (styles/animated-sign-panel bottom-value)}
(when wrong-password?
@ -119,7 +119,7 @@
;; "Sign Transaction >" button
(defn- sign-transaction-button [amount-error to amount sufficient-funds? sufficient-gas? modal? online?]
(let [sign-enabled? (and (nil? amount-error)
(or modal? (not (empty? to))) ;;NOTE(goranjovic) - contract creation will have empty `to`
(or modal? (not (empty? to))) ;;NOTE(goranjovic) - contract creation will have empty `to`
(not (nil? amount))
sufficient-funds?
sufficient-gas?
@ -129,19 +129,32 @@
[react/view]
[button/button {:style components.styles/flex
:disabled? (not sign-enabled?)
:on-press #(re-frame/dispatch [:set-in
[:wallet :send-transaction :show-password-input?]
true])
:on-press #(re-frame/dispatch [:wallet.ui/sign-transaction-button-clicked])
:text-style {:color :white}
:accessibility-label :sign-transaction-button}
(i18n/label :t/transactions-sign-transaction)
[vector-icons/icon :main-icons/next {:color (if sign-enabled? colors/white colors/white-light-transparent)}]]]))
(defn- render-send-transaction-view [{:keys [modal? transaction scroll advanced? network all-tokens amount-input network-status]}]
(defn signing-phrase-view [signing-phrase]
[react/view {:flex-direction :column
:align-items :center
:margin-top 10}
[react/view (assoc styles/signing-phrase-container :width "90%" :height 40)
[react/text {:accessibility-label :signing-phrase-text
:style {:padding-vertical 16
:text-align :center}}
signing-phrase]]
[react/text {:style {:color :white
:text-align :center
:font-size 12
:padding-vertical 14}}
(i18n/label :t/signing-phrase-warning)]])
(defn- render-send-transaction-view [{:keys [modal? transaction scroll advanced? keycard? signing-phrase network all-tokens amount-input network-status]}]
(let [{:keys [amount amount-text amount-error asset-error show-password-input? to to-name sufficient-funds?
sufficient-gas? in-progress? from-chat? symbol]} transaction
chain (ethereum/network->chain-keyword network)
native-currency (tokens/native-currency chain)
chain (ethereum/network->chain-keyword network)
native-currency (tokens/native-currency chain)
{:keys [decimals] :as token} (tokens/asset-for all-tokens chain symbol)
online? (= :online network-status)]
[wallet.components/simple-screen {:avoid-keyboard? (not modal?)
@ -172,7 +185,9 @@
:amount-text amount-text
:input-options {:on-change-text #(re-frame/dispatch [:wallet.send/set-and-validate-amount % symbol decimals])
:ref (partial reset! amount-input)}} token]
[advanced-options advanced? native-currency transaction scroll]]]
[advanced-options advanced? native-currency transaction scroll]
(when keycard?
[signing-phrase-view signing-phrase])]]
(if show-password-input?
[enter-password-buttons in-progress?
#(re-frame/dispatch [:wallet/cancel-entering-password])
@ -186,11 +201,11 @@
;; MAIN SEND TRANSACTION VIEW
(defn- send-transaction-view [{:keys [scroll] :as opts}]
(let [amount-input (atom nil)
handler (fn [_]
(when (and scroll @scroll @amount-input
(.isFocused @amount-input))
(log/debug "Amount field focused, scrolling down")
(.scrollToEnd @scroll)))]
handler (fn [_]
(when (and scroll @scroll @amount-input
(.isFocused @amount-input))
(log/debug "Amount field focused, scrolling down")
(.scrollToEnd @scroll)))]
(reagent/create-class
{:component-will-mount (fn [_]
;;NOTE(goranjovic): keyboardDidShow is for android and keyboardWillShow for ios
@ -201,33 +216,41 @@
;; SEND TRANSACTION FROM WALLET (CHAT)
(defview send-transaction []
(letsubs [transaction [:wallet.send/transaction]
advanced? [:wallet.send/advanced?]
network [:account/network]
scroll (atom nil)
(letsubs [transaction [:wallet.send/transaction]
advanced? [:wallet.send/advanced?]
network [:account/network]
scroll (atom nil)
network-status [:network-status]
all-tokens [:wallet/all-tokens]]
all-tokens [:wallet/all-tokens]
signing-phrase [:wallet.send/signing-phrase-with-padding]
keycard? [:keycard-account?]]
[send-transaction-view {:modal? false
:transaction transaction
:scroll scroll
:advanced? advanced?
:keycard? keycard?
:signing-phrase signing-phrase
:network network
:all-tokens all-tokens
:network-status network-status}]))
;; SEND TRANSACTION FROM DAPP
(defview send-transaction-modal []
(letsubs [transaction [:wallet.send/transaction]
advanced? [:wallet.send/advanced?]
network [:account/network]
scroll (atom nil)
(letsubs [transaction [:wallet.send/transaction]
advanced? [:wallet.send/advanced?]
network [:account/network]
scroll (atom nil)
network-status [:network-status]
all-tokens [:wallet/all-tokens]]
all-tokens [:wallet/all-tokens]
signing-phrase [:wallet.send/signing-phrase-with-padding]
keycard? [:keycard-account?]]
(if transaction
[send-transaction-view {:modal? true
:transaction transaction
:scroll scroll
:advanced? advanced?
:keycard? keycard?
:signing-phrase signing-phrase
:network network
:all-tokens all-tokens
:network-status network-status}]

View File

@ -7,6 +7,7 @@
[status-im.ui.screens.wallet.components.views :as components]
[status-im.ui.screens.wallet.components.views :as wallet.components]
[status-im.ui.screens.wallet.send.styles :as styles]
[status-im.ui.screens.wallet.send.views :as wallet.send.views]
[status-im.ui.screens.wallet.main.views :as wallet.main.views]
[status-im.ui.components.toolbar.actions :as actions]
[status-im.ui.components.toolbar.view :as toolbar]
@ -30,10 +31,11 @@
#(actions/default-handler)))]
[toolbar/content-title {:color :white} title]]))
(defview enter-password-buttons [value-atom spinning? cancel-handler sign-handler sign-label]
(defview enter-password-buttons [value-atom {:keys [spinning? keycard?]} cancel-handler sign-handler sign-label]
(letsubs [network-status [:network-status]]
(let [password (:password @value-atom)
sign-enabled? (and (not (nil? password)) (not= password ""))]
sign-enabled? (or keycard?
(and (not (nil? password)) (not= password "")))]
[bottom-buttons/bottom-buttons
styles/sign-buttons
[button/button {:style components.styles/flex
@ -82,7 +84,7 @@
;; SIGN MESSAGE FROM DAPP
(defview sign-message-modal []
(letsubs [value-atom (reagent/atom nil)
{:keys [decoded-data in-progress? typed?] :as screen-params} [:get-screen-params :wallet-sign-message-modal]
{:keys [decoded-data in-progress? typed? keycard? signing-phrase] :as screen-params} [:get-screen-params :wallet-sign-message-modal]
network-status [:network-status]]
[wallet.components/simple-screen {:status-bar-type :modal-wallet}
[toolbar true (i18n/label :t/sign-message)]
@ -96,17 +98,24 @@
[components/amount-input
{:disabled? true
:input-options {:multiline true
:height 100}
:height (if typed? 300 100)}
:amount-text (if typed?
(str "Domain\n" (:domain decoded-data) "\nMessage\n" (:message decoded-data))
decoded-data)}
nil]]]]
[enter-password-buttons value-atom false
nil]]]
(when keycard?
[wallet.send.views/signing-phrase-view signing-phrase])]
[enter-password-buttons
value-atom
{:spinning? false :keycard? keycard?}
#(re-frame/dispatch [:wallet/discard-transaction-navigate-back])
#(re-frame/dispatch [:wallet/sign-message typed? (merge screen-params @value-atom)
#(re-frame/dispatch [:wallet.ui/sign-message-button-clicked
typed?
(merge screen-params @value-atom)
(fn []
(swap! value-atom assoc :wrong-password? true))])
:t/transactions-sign]
[password-input-panel value-atom :t/signing-message-phrase-description false]
(when-not keycard?
[password-input-panel value-atom :t/signing-message-phrase-description false])
(when in-progress?
[react/view styles/processing-view])]]))

View File

@ -635,6 +635,7 @@
"wallet-choose-from-contacts": "Choose from Contacts",
"send-sending-to": "to {{recipient-name}}",
"signing-phrase-description": "If you recognize these words, enter your login password to sign the transaction",
"signing-phrase-warning": "Only confirm the transaction if you recognize\n your three words",
"currency-display-name-mad": "Moroccan Dirham",
"here-is-your-signing-phrase": "Here is your signing phrase. You will use it to verify your transactions. *Write it down and keep it safe!*",
"wants-to-access-profile": "wants to access to your profile",