new wallet sign with keycard flow
Signed-off-by: Dmitry Novotochinov <dmitry.novot@gmail.com>
This commit is contained in:
parent
068d726164
commit
ac25f6766d
Binary file not shown.
After Width: | Height: | Size: 5.3 KiB |
|
@ -28,6 +28,7 @@
|
|||
[status-im.fleet.core :as fleet]
|
||||
[status-im.group-chats.core :as group-chats]
|
||||
[status-im.hardwallet.core :as hardwallet]
|
||||
[status-im.signing.keycard :as signing.keycard]
|
||||
[status-im.i18n :as i18n]
|
||||
[status-im.init.core :as init]
|
||||
[status-im.log-level.core :as log-level]
|
||||
|
@ -1056,11 +1057,6 @@
|
|||
(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 _]
|
||||
|
@ -1343,16 +1339,6 @@
|
|||
(fn [cofx _]
|
||||
(hardwallet/navigate-to-reset-card-screen cofx)))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:hardwallet/sign
|
||||
(fn [cofx _]
|
||||
(hardwallet/sign cofx)))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:hardwallet/prepare-to-sign
|
||||
(fn [cofx _]
|
||||
(hardwallet/prepare-to-sign cofx)))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:hardwallet/unblock-pin
|
||||
(fn [cofx _]
|
||||
|
|
|
@ -1123,6 +1123,7 @@
|
|||
nil)))
|
||||
|
||||
(fx/defn sign
|
||||
{:events [:hardwallet/sign]}
|
||||
[{:keys [db] :as cofx}]
|
||||
(let [card-connected? (get-in db [:hardwallet :card-connected?])
|
||||
pairing (get-pairing db)
|
||||
|
@ -1140,24 +1141,25 @@
|
|||
:pairing pairing
|
||||
:pin pin}}
|
||||
(fx/merge cofx
|
||||
{:db (assoc-in db [:hardwallet :on-card-connected] :hardwallet/sign)}
|
||||
{:db (-> db
|
||||
(assoc-in [:signing/sign :keycard-step] :signing)
|
||||
(assoc-in [:hardwallet :on-card-connected] :hardwallet/sign))}
|
||||
(when-not keycard-match?
|
||||
(show-wrong-keycard-alert card-connected?))
|
||||
(navigate-to-connect-screen :hardwallet-connect-sign)))))
|
||||
(show-wrong-keycard-alert card-connected?))))))
|
||||
|
||||
(fx/defn prepare-to-sign
|
||||
{:events [:hardwallet/prepare-to-sign]}
|
||||
[{:keys [db] :as cofx}]
|
||||
(let [card-connected? (get-in db [:hardwallet :card-connected?])
|
||||
pairing (get-pairing db)]
|
||||
(if card-connected?
|
||||
(get-application-info cofx pairing :hardwallet/sign)
|
||||
(fx/merge cofx
|
||||
{:db (assoc-in db [:hardwallet :on-card-connected] :hardwallet/prepare-to-sign)}
|
||||
(navigation/navigate-to-cofx
|
||||
(if (= (:view-id db) :enter-pin-modal)
|
||||
:hardwallet-connect-modal
|
||||
:hardwallet-connect-sign)
|
||||
nil)))))
|
||||
{:db (assoc-in db [:signing/sign :keycard-step] :signing)}
|
||||
(get-application-info pairing :hardwallet/sign))
|
||||
(fx/merge cofx
|
||||
{:db (-> db
|
||||
(assoc-in [:signing/sign :keycard-step] :connect)
|
||||
(assoc-in [:hardwallet :on-card-connected] :hardwallet/prepare-to-sign))}))))
|
||||
|
||||
(fx/defn import-account
|
||||
[{:keys [db] :as cofx}]
|
||||
|
@ -1590,23 +1592,22 @@
|
|||
{: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
|
||||
[_ signature]
|
||||
(let [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'}]}))
|
||||
[:signing/sign-message-completed (types/clj->json {:result signature'})]}))
|
||||
|
||||
(fx/defn on-sign-success
|
||||
{:events [:hardwallet.callback/on-sign-success]}
|
||||
[{:keys [db] :as cofx} signature]
|
||||
(log/debug "[hardwallet] sign success: " signature)
|
||||
(let [transaction (get-in db [:hardwallet :transaction])]
|
||||
(let [transaction (get-in db [:hardwallet :transaction])
|
||||
tx-obj (select-keys transaction [:from :to :value :gas :gasPrice])]
|
||||
(fx/merge cofx
|
||||
{:db (-> db
|
||||
(assoc-in [:hardwallet :pin :sign] [])
|
||||
|
@ -1618,30 +1619,28 @@
|
|||
(if transaction
|
||||
(send-transaction-with-signature {:transaction (types/clj->json transaction)
|
||||
:signature signature
|
||||
:on-completed #(re-frame/dispatch [:wallet.callback/transaction-completed (types/json->clj %)])})
|
||||
:on-completed #(re-frame/dispatch [:signing/transaction-completed % tx-obj])})
|
||||
(sign-message-completed signature)))))
|
||||
|
||||
(fx/defn on-sign-error
|
||||
[{:keys [db] :as cofx} error]
|
||||
(log/debug "[hardwallet] sign error: " error)
|
||||
(let [tag-was-lost? (= "Tag was lost." (:error error))
|
||||
modal? (get-in db [:navigation/screen-params :wallet-send-modal-stack :modal?])]
|
||||
(let [tag-was-lost? (= "Tag was lost." (:error error))]
|
||||
(fx/merge cofx
|
||||
(if tag-was-lost?
|
||||
(fx/merge cofx
|
||||
{:db (-> db
|
||||
(assoc-in [:hardwallet :on-card-connected] :hardwallet/prepare-to-sign)
|
||||
(assoc-in [:hardwallet :pin :status] nil))
|
||||
(assoc-in [:hardwallet :pin :status] nil)
|
||||
(assoc-in [:signing/sign :keycard-step] :connect))
|
||||
:utils/show-popup {:title (i18n/label :t/error)
|
||||
:content (i18n/label :t/cannot-read-card)}}
|
||||
(navigate-to-connect-screen :hardwallet-connect-sign)))
|
||||
:content (i18n/label :t/cannot-read-card)}}))
|
||||
(if (re-matches pin-mismatch-error (:error error))
|
||||
(fx/merge cofx
|
||||
{:db (update-in db [:hardwallet :pin] merge {:status :error
|
||||
{:db (-> db
|
||||
(update-in [:hardwallet :pin] merge {:status :error
|
||||
:sign []
|
||||
:error-label :t/pin-mismatch})}
|
||||
(navigation/navigate-to-cofx (if modal?
|
||||
:enter-pin-modal
|
||||
:enter-pin-sign) nil)
|
||||
:error-label :t/pin-mismatch})
|
||||
(assoc-in [:signing/sign :keycard-step] :pin))}
|
||||
(get-application-info (get-pairing db) nil))
|
||||
(show-wrong-keycard-alert cofx true)))))
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
:secret-keys (js-require/js-require "./resources/images/ui/secret-keys.png")
|
||||
:keycard-lock (js-require/js-require "./resources/images/ui/keycard-lock.png")
|
||||
:keycard (js-require/js-require "./resources/images/ui/keycard.png")
|
||||
:keycard-logo (js-require/js-require "./resources/images/ui/keycard-logo.png")
|
||||
:keycard-phone (js-require/js-require "./resources/images/ui/keycard-phone.png")
|
||||
:keycard-connection (js-require/js-require "./resources/images/ui/keycard-connection.png")
|
||||
:keycard-nfc-on (js-require/js-require "./resources/images/ui/keycard-nfc-on.png")
|
||||
|
|
|
@ -166,13 +166,14 @@
|
|||
|
||||
(fx/defn show-sign [{:keys [db] :as cofx}]
|
||||
(let [{:signing/keys [queue]} db
|
||||
{{:keys [gas gasPrice] :as tx-obj} :tx-obj {:keys [data typed?] :as message} :message :as tx} (last queue)]
|
||||
{{:keys [gas gasPrice] :as tx-obj} :tx-obj {:keys [data typed?] :as message} :message :as tx} (last queue)
|
||||
keycard-account? (boolean (get-in db [:account/account :keycard-instance-uid]))]
|
||||
(if message
|
||||
{:db (assoc db
|
||||
:signing/in-progress? true
|
||||
:signing/queue (drop-last queue)
|
||||
:signing/tx tx
|
||||
:signing/sign {:type :password
|
||||
:signing/sign {:type (if keycard-account? :keycard :password)
|
||||
:formatted-data (if typed? (types/json->clj data) (ethereum/hex-to-utf8 data))})}
|
||||
(fx/merge cofx
|
||||
{:db
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
(ns status-im.signing.keycard
|
||||
(:require [re-frame.core :as re-frame]
|
||||
[status-im.utils.fx :as fx]
|
||||
[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]))
|
||||
|
||||
(re-frame/reg-fx
|
||||
::hash-transaction
|
||||
(fn [{:keys [transaction 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 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))}
|
||||
data
|
||||
(assoc :data data)
|
||||
nonce
|
||||
(assoc :nonce nonce))))
|
||||
|
||||
(fx/defn hash-message
|
||||
[_ {:keys [data typed?]}]
|
||||
(if typed?
|
||||
{::hash-typed-data {:data data
|
||||
:on-completed #(re-frame/dispatch [:signing.keycard.callback/hash-message-completed %])}}
|
||||
{::hash-message {:message (ethereum/naked-address data)
|
||||
:on-completed #(re-frame/dispatch [:signing.keycard.callback/hash-message-completed %])}}))
|
||||
|
||||
(fx/defn hash-message-completed
|
||||
{:events [:signing.keycard.callback/hash-message-completed]}
|
||||
[{:keys [db]} result]
|
||||
(let [{:keys [result error]} (types/json->clj result)]
|
||||
{:db (-> db
|
||||
(assoc-in [:hardwallet :hash] result))}))
|
||||
|
||||
(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 %])}})
|
||||
|
||||
(fx/defn hash-transaction-completed
|
||||
{:events [:signing.keycard.callback/hash-transaction-completed]}
|
||||
[{:keys [db]} result]
|
||||
(let [{:keys [transaction hash]} (:result (types/json->clj result))]
|
||||
{:db (-> db
|
||||
(assoc-in [:hardwallet :transaction] transaction)
|
||||
(assoc-in [:hardwallet :hash] hash))}))
|
||||
|
||||
(fx/defn sign-with-keycard
|
||||
{:events [:signing.ui/sign-with-keycard-pressed]}
|
||||
[{:keys [db] :as cofx}]
|
||||
(let [message (get-in db [:signing/tx :message])]
|
||||
(fx/merge cofx
|
||||
{:db (-> db
|
||||
(assoc-in [:hardwallet :pin :enter-step] :sign)
|
||||
(assoc-in [:signing/sign :keycard-step] :pin)
|
||||
(assoc-in [:signing/sign :type] :keycard))}
|
||||
(if message
|
||||
(hash-message message)
|
||||
(hash-transaction)))))
|
|
@ -226,6 +226,11 @@
|
|||
:<- [:dimensions/window]
|
||||
:width)
|
||||
|
||||
(re-frame/reg-sub
|
||||
:dimensions/window-height
|
||||
:<- [:dimensions/window]
|
||||
:height)
|
||||
|
||||
(re-frame/reg-sub
|
||||
:get-screen-params
|
||||
:<- [:screen-params]
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
(def black-transparent (alpha black 0.1)) ;; Used as background color for rounded button on dark background and as background color for containers like "Backup seed phrase"
|
||||
(def black-transparent-40 (alpha black 0.4))
|
||||
(def gray-light black-transparent) ;; Used as divider color
|
||||
(def black-light "#2d2d2d")
|
||||
|
||||
;; DARK GREY
|
||||
(def gray "#939ba1") ;; Dark grey, used as a background for a light foreground and as section header and secondary text color
|
||||
|
|
|
@ -21,10 +21,10 @@
|
|||
{:color colors/red
|
||||
:text-align :center})
|
||||
|
||||
(def center-container
|
||||
(defn center-container [title]
|
||||
{:flex-direction :column
|
||||
:align-items :center
|
||||
:margin-top 28})
|
||||
:margin-top (if title 28 5)})
|
||||
|
||||
(def center-title-text
|
||||
{:typography :header})
|
||||
|
|
|
@ -75,12 +75,14 @@
|
|||
(let [enabled? (not= status :verifying)]
|
||||
[react/scroll-view
|
||||
[react/view styles/pin-container
|
||||
[react/view styles/center-container
|
||||
[react/view (styles/center-container title-label)
|
||||
(when title-label
|
||||
[react/text {:style styles/center-title-text}
|
||||
(i18n/label title-label)]
|
||||
(i18n/label title-label)])
|
||||
(when description-label
|
||||
[react/text {:style styles/create-pin-text
|
||||
:number-of-lines 2}
|
||||
(i18n/label description-label)]
|
||||
(i18n/label description-label)])
|
||||
(when retry-counter
|
||||
[react/text {:style {:font-weight "700"
|
||||
:padding-top 10
|
||||
|
|
|
@ -18,7 +18,9 @@
|
|||
[status-im.ui.screens.signing.sheets :as sheets]
|
||||
[status-im.ethereum.tokens :as tokens]
|
||||
[clojure.string :as string]
|
||||
[status-im.ui.screens.signing.styles :as styles]))
|
||||
[status-im.ui.screens.signing.styles :as styles]
|
||||
[status-im.react-native.resources :as resources]
|
||||
[status-im.ui.screens.hardwallet.pin.views :as pin.views]))
|
||||
|
||||
(defn hide-panel-anim
|
||||
[bottom-anim-value alpha-value window-height]
|
||||
|
@ -95,14 +97,79 @@
|
|||
[react/view {:padding 6}
|
||||
[react/text {:style {:color colors/blue}} (i18n/label :t/cancel)]]]])
|
||||
|
||||
(views/defview password-view [{:keys [type error in-progress? enabled?]}]
|
||||
(views/defview keycard-pin-view []
|
||||
(views/letsubs [pin [:hardwallet/pin]]
|
||||
[react/view
|
||||
[pin.views/pin-view
|
||||
{:pin pin
|
||||
:retry-counter nil
|
||||
:step :sign
|
||||
:status nil
|
||||
:error-label nil}]]))
|
||||
|
||||
(defn- keycard-connect-view []
|
||||
[react/view {:padding-vertical 20
|
||||
:flex 1
|
||||
:align-items :center
|
||||
:justify-content :center}
|
||||
[react/image {:source (resources/get-image :keycard-phone)
|
||||
:resize-mode :center
|
||||
:style {:width 160
|
||||
:height 170}}]
|
||||
[react/view {:margin-top 10}
|
||||
[react/text {:style {:text-align :center
|
||||
:color colors/gray}}
|
||||
(i18n/label :t/hold-card)]]])
|
||||
|
||||
(defn- keycard-processing-view []
|
||||
[react/view {:flex-direction :column
|
||||
:flex 1
|
||||
:justify-content :center
|
||||
:align-items :center}
|
||||
[react/activity-indicator {:size :large
|
||||
:animating true}]
|
||||
[react/text {:style {:margin-top 16
|
||||
:color colors/gray}}
|
||||
(i18n/label :t/processing)]])
|
||||
|
||||
(defn- sign-with-keycard-button
|
||||
[amount-error gas-error]
|
||||
[button/button {:on-press #(re-frame/dispatch [:signing.ui/sign-with-keycard-pressed])
|
||||
:text-style {:padding-right 2
|
||||
:padding-left 16}
|
||||
:style {:background-color colors/black-light
|
||||
:padding-top 2
|
||||
:border-radius 8}
|
||||
:disabled? (or amount-error gas-error)}
|
||||
(i18n/label :t/sign-with)
|
||||
[react/view {:padding-right 16}
|
||||
[react/image {:source (resources/get-image :keycard-logo)
|
||||
:style {:width 64
|
||||
:margin-bottom 7
|
||||
:height 26}}]]])
|
||||
|
||||
(defn- signing-phrase-view [phrase]
|
||||
[react/view {:align-items :center}
|
||||
[react/text {:style {:color colors/gray :padding-bottom 8}} (i18n/label :t/signing-phrase)]
|
||||
[react/text phrase]])
|
||||
|
||||
(defn- keycard-view
|
||||
[{:keys [keycard-step]} phrase]
|
||||
[react/view {:height 450}
|
||||
[signing-phrase-view phrase]
|
||||
(case keycard-step
|
||||
:pin [keycard-pin-view]
|
||||
:connect [keycard-connect-view]
|
||||
:signing [keycard-processing-view]
|
||||
[react/view {:align-items :center :margin-top 16 :margin-bottom 40}
|
||||
[sign-with-keycard-button nil nil]])])
|
||||
|
||||
(views/defview password-view [{:keys [type error in-progress? enabled?] :as sign}]
|
||||
(views/letsubs [phrase [:signing/phrase]]
|
||||
(case type
|
||||
:password
|
||||
[react/view {:padding-top 16 :padding-bottom 16}
|
||||
[react/view {:align-items :center}
|
||||
[react/text {:style {:color colors/gray :padding-bottom 8}} (i18n/label :t/signing-phrase)]
|
||||
[react/text phrase]]
|
||||
[signing-phrase-view phrase]
|
||||
[text-input/text-input-with-label
|
||||
{:secure-text-entry true
|
||||
:placeholder (i18n/label :t/enter-password)
|
||||
|
@ -119,10 +186,12 @@
|
|||
[button/primary-button {:on-press #(re-frame/dispatch [:signing.ui/sign-is-pressed])
|
||||
:disabled? (not enabled?)}
|
||||
(i18n/label :t/transactions-sign)])]]
|
||||
:keycard
|
||||
[keycard-view sign phrase]
|
||||
[react/view])))
|
||||
|
||||
(views/defview message-sheet []
|
||||
(views/letsubs [{:keys [formatted-data] :as sign} [:signing/sign]]
|
||||
(views/letsubs [{:keys [formatted-data type] :as sign} [:signing/sign]]
|
||||
[react/view styles/message
|
||||
[react/view styles/message-header
|
||||
[react/text {:style {:typography :title-bold}} (i18n/label :t/signing-a-message)]
|
||||
|
@ -140,7 +209,8 @@
|
|||
(views/letsubs [fee [:signing/fee]
|
||||
sign [:signing/sign]
|
||||
chain [:ethereum/chain-keyword]
|
||||
{:keys [amount-error gas-error]} [:signing/amount-errors]]
|
||||
{:keys [amount-error gas-error]} [:signing/amount-errors]
|
||||
keycard-account? [:keycard-account?]]
|
||||
(let [display-symbol (wallet.utils/display-symbol token)
|
||||
fee-display-symbol (wallet.utils/display-symbol (tokens/native-currency chain))]
|
||||
[react/view styles/sheet
|
||||
|
@ -167,9 +237,11 @@
|
|||
{:content (fn [] [sheets/fee-bottom-sheet fee-display-symbol])
|
||||
:content-height 270}])}]
|
||||
[react/view {:align-items :center :margin-top 16 :margin-bottom 40}
|
||||
(if keycard-account?
|
||||
[sign-with-keycard-button amount-error gas-error]
|
||||
[button/primary-button {:on-press #(re-frame/dispatch [:set :signing/sign {:type :password}])
|
||||
:disabled? (or amount-error gas-error)}
|
||||
(i18n/label :t/sign-with-password)]]])])))
|
||||
(i18n/label :t/sign-with-password)])]])])))
|
||||
|
||||
(defn signing-view [tx window-height]
|
||||
(let [bottom-anim-value (anim/create-value window-height)
|
||||
|
|
|
@ -1076,6 +1076,7 @@
|
|||
"signing-phrase" : "Signing phrase",
|
||||
"network-fee" : "Network fee",
|
||||
"sign-with-password" : "Sign with password",
|
||||
"sign-with" : "Sign with",
|
||||
"signing-a-message" : "Signing a message",
|
||||
"select-chat" : "Select chat to start messaging",
|
||||
"etherscan-lookup": "Look up on Etherscan",
|
||||
|
|
Loading…
Reference in New Issue