From 949e78a17e7a7a9367ab264b09b34c0b88d51df9 Mon Sep 17 00:00:00 2001 From: flexsurfer Date: Tue, 10 Dec 2024 18:07:45 +0100 Subject: [PATCH] [#21577] Keycard [Wallet] - Derives next account for profile key pair (#21753) --- .../standard_authentication/events.cljs | 64 ++++++++++------- .../standard_auth/slide_button/view.cljs | 37 +++++----- .../contact_requests/bottom_drawer/view.cljs | 43 ++++++------ .../actions/request_to_join/view.cljs | 9 ++- .../contexts/communities/overview/view.cljs | 52 ++++++++------ src/status_im/contexts/keycard/events.cljs | 28 +++++++- .../keycard/feature_unavailable/events.cljs | 7 +- .../settings/screens/password/view.cljs | 56 ++++++++------- .../wallet/keypairs_and_accounts/view.cljs | 6 +- .../syncing/syncing_devices_list/view.cljs | 10 ++- .../wallet/account/tabs/about/view.cljs | 6 +- .../create_account/select_keypair/view.cljs | 3 +- .../add_account/create_account/view.cljs | 68 ++++++++++++------- src/status_im/contexts/wallet/events.cljs | 5 +- .../send/transaction_confirmation/view.cljs | 20 ++++-- .../wallet/swap/set_spending_cap/view.cljs | 17 +++-- .../wallet/swap/swap_confirmation/view.cljs | 10 ++- src/status_im/subs/wallet/wallet.cljs | 4 +- src/utils/address.cljs | 11 +++ 19 files changed, 292 insertions(+), 164 deletions(-) diff --git a/src/status_im/common/standard_authentication/events.cljs b/src/status_im/common/standard_authentication/events.cljs index 9f9b44d62e..3c3d0117ed 100644 --- a/src/status_im/common/standard_authentication/events.cljs +++ b/src/status_im/common/standard_authentication/events.cljs @@ -10,19 +10,44 @@ [utils.re-frame :as rf] [utils.security.core :as security])) -(rf/reg-fx :effects.keycard/call-on-auth-success - (fn [on-auth-success] - (when on-auth-success (on-auth-success "")))) +(defn- handle-password-success + [has-partially-operable-accounts? on-auth-success password] + (let [sha3-pwd (security/hash-masked-password password) + on-auth-success-callback #(on-auth-success sha3-pwd)] + (rf/dispatch [:standard-auth/set-success true]) + (rf/dispatch [:standard-auth/reset-login-password]) + (if has-partially-operable-accounts? + (rf/dispatch [:wallet/make-partially-operable-accounts-fully-operable + {:password sha3-pwd + :on-success on-auth-success-callback + :on-error on-auth-success-callback}]) + (on-auth-success-callback)))) (defn authorize - [{:keys [db]} [{:keys [on-auth-success keycard-supported?] :as args}]] - (let [key-uid (get-in db [:profile/profile :key-uid]) - keycard? (get-in db [:profile/profile :keycard-pairing])] + [{:keys [db]} [{:keys [on-auth-success] :as args}]] + (let [key-uid (get-in db [:profile/profile :key-uid]) + keycard-profile? (get-in db [:profile/profile :keycard-pairing])] {:fx - [(if keycard? - (if keycard-supported? - [:effects.keycard/call-on-auth-success on-auth-success] - [:dispatch [:keycard/feature-unavailable-show]]) + [(if keycard-profile? + [:dispatch + [:standard-auth/authorize-with-keycard + {:on-complete + (fn [pin] + (rf/dispatch + [:keycard/connect + {:key-uid key-uid + :on-success + (fn [] + (rf/dispatch + [:keycard/get-keys + {:pin pin + :on-success (fn [{:keys [encryption-public-key]}] + (rf/dispatch [:keycard/disconnect]) + (handle-password-success false + on-auth-success + encryption-public-key)) + :on-failure #(rf/dispatch [:keycard/on-action-with-pin-error + %])}]))}]))}]] [:effects.biometric/check-if-available {:key-uid key-uid :on-success #(rf/dispatch [:standard-auth/authorize-with-biometric args]) @@ -84,21 +109,12 @@ (defn- bottom-sheet-password-view [{:keys [on-press-biometric on-auth-success auth-button-icon-left auth-button-label]}] (fn [] - (let [has-partially-operable-accounts? (rf/sub [:wallet/has-partially-operable-accounts?]) - handle-password-success - (fn [password] - (let [sha3-pwd (security/hash-masked-password password) - on-auth-success-callback #(on-auth-success sha3-pwd)] - (rf/dispatch [:standard-auth/set-success true]) - (rf/dispatch [:standard-auth/reset-login-password]) - (if has-partially-operable-accounts? - (rf/dispatch [:wallet/make-partially-operable-accounts-fully-operable - {:password sha3-pwd - :on-success on-auth-success-callback - :on-error on-auth-success-callback}]) - (on-auth-success-callback))))] + (let [has-partially-operable-accounts? (rf/sub [:wallet/has-partially-operable-accounts?])] [enter-password/view - {:on-enter-password handle-password-success + {:on-enter-password #(handle-password-success + has-partially-operable-accounts? + on-auth-success + %) :on-press-biometrics on-press-biometric :button-icon-left auth-button-icon-left :button-label auth-button-label}]))) diff --git a/src/status_im/common/standard_authentication/standard_auth/slide_button/view.cljs b/src/status_im/common/standard_authentication/standard_auth/slide_button/view.cljs index 4c4ce5c9ec..222dfa21b3 100644 --- a/src/status_im/common/standard_authentication/standard_auth/slide_button/view.cljs +++ b/src/status_im/common/standard_authentication/standard_auth/slide_button/view.cljs @@ -9,26 +9,25 @@ (defn view [{:keys [track-text customization-color auth-button-label on-auth-success on-auth-fail - auth-button-icon-left size blur? container-style disabled? dependencies keycard-supported?] + auth-button-icon-left size blur? container-style disabled? dependencies on-complete] :or {container-style {:flex 1}}}] - (let [theme (quo.theme/use-theme) - auth-method (rf/sub [:auth-method]) - biometric-auth? (= auth-method constants/auth-method-biometric) - on-complete (rn/use-callback - (fn [reset-slider-fn] - (js/setTimeout #(reset-slider-fn false) 500) - (rf/dispatch - [:standard-auth/authorize - {:auth-button-icon-left auth-button-icon-left - :theme theme - :blur? blur? - :keycard-supported? keycard-supported? - :biometric-auth? biometric-auth? - :on-auth-success on-auth-success - :on-auth-fail on-auth-fail - :auth-button-label auth-button-label}])) - (vec (conj dependencies on-auth-success on-auth-fail))) - biometric-type (rf/sub [:biometrics/supported-type])] + (let [theme (quo.theme/use-theme) + auth-method (rf/sub [:auth-method]) + biometric-auth? (= auth-method constants/auth-method-biometric) + on-complete-callback (rn/use-callback + (fn [reset-slider-fn] + (js/setTimeout #(reset-slider-fn false) 500) + (rf/dispatch [:standard-auth/authorize + {:auth-button-icon-left auth-button-icon-left + :theme theme + :blur? blur? + :biometric-auth? biometric-auth? + :on-auth-success on-auth-success + :on-auth-fail on-auth-fail + :auth-button-label auth-button-label}])) + (vec (conj dependencies on-auth-success on-auth-fail))) + on-complete (or on-complete on-complete-callback) + biometric-type (rf/sub [:biometrics/supported-type])] [quo/slide-button {:container-style container-style :size size diff --git a/src/status_im/contexts/chat/messenger/messages/contact_requests/bottom_drawer/view.cljs b/src/status_im/contexts/chat/messenger/messages/contact_requests/bottom_drawer/view.cljs index 87bb6cda38..7ab290d521 100644 --- a/src/status_im/contexts/chat/messenger/messages/contact_requests/bottom_drawer/view.cljs +++ b/src/status_im/contexts/chat/messenger/messages/contact_requests/bottom_drawer/view.cljs @@ -11,30 +11,35 @@ [{:keys [contact-id]}] (let [{:keys [contact-request-state community-id - chat-name]} (rf/sub [:chats/current-chat-chat-view]) - chat-type (rf/sub [:chats/chat-type]) - [primary-name _] (if (= chat-type :public-chat) - [(str "#" chat-name) ""] - (rf/sub [:contacts/contact-two-names-by-identity contact-id])) - community-chat? (= chat-type :community-chat) - joined (when community-chat? - (rf/sub [:communities/community-joined community-id])) - pending? (when community-chat? - (rf/sub [:communities/my-pending-request-to-join community-id])) - contact-request-send? (or (not contact-request-state) - (= contact-request-state - constants/contact-request-state-none)) - contact-request-received? (= contact-request-state - constants/contact-request-state-received) - contact-request-pending? (= contact-request-state - constants/contact-request-state-sent)] + chat-name]} (rf/sub [:chats/current-chat-chat-view]) + chat-type (rf/sub [:chats/chat-type]) + [primary-name _] (if (= chat-type :public-chat) + [(str "#" chat-name) ""] + (rf/sub [:contacts/contact-two-names-by-identity contact-id])) + community-chat? (= chat-type :community-chat) + joined (when community-chat? + (rf/sub [:communities/community-joined community-id])) + pending? (when community-chat? + (rf/sub [:communities/my-pending-request-to-join community-id])) + contact-request-send? (or (not contact-request-state) + (= contact-request-state + constants/contact-request-state-none)) + contact-request-received? (= contact-request-state + constants/contact-request-state-received) + contact-request-pending? (= contact-request-state + constants/contact-request-state-sent) + keycard? (rf/sub [:keycard/keycard-profile?]) + keycard-feature-unavailable (rn/use-callback + #(rf/dispatch [:keycard/feature-unavailable-show]))] [rn/view {:style style/container} [quo/permission-context {:blur? true :on-press (cond (and community-chat? (not pending?) (not joined)) - #(rf/dispatch [:open-modal :community-account-selection-sheet - {:community-id community-id}]) + (if keycard? + keycard-feature-unavailable + #(rf/dispatch [:open-modal :community-account-selection-sheet + {:community-id community-id}])) (not community-chat?) #(rf/dispatch [:chat.ui/show-profile contact-id])) diff --git a/src/status_im/contexts/communities/actions/request_to_join/view.cljs b/src/status_im/contexts/communities/actions/request_to_join/view.cljs index b8511c9999..41f4feb401 100644 --- a/src/status_im/contexts/communities/actions/request_to_join/view.cljs +++ b/src/status_im/contexts/communities/actions/request_to_join/view.cljs @@ -27,7 +27,10 @@ (fn [] (let [theme (quo.theme/use-theme) {:keys [id]} (rf/sub [:get-screen-params]) - {:keys [color name images]} (rf/sub [:communities/community id])] + {:keys [color name images]} (rf/sub [:communities/community id]) + keycard? (rf/sub [:keycard/keycard-profile?]) + keycard-feature-unavailable (rn/use-callback + #(rf/dispatch [:keycard/feature-unavailable-show]))] [rn/safe-area-view {:flex 1} [gesture/scroll-view {:style style/container} [rn/view style/page-container @@ -59,7 +62,9 @@ (i18n/label :t/cancel)] [quo/button {:accessibility-label :join-community-button - :on-press #(join-community-and-navigate-back id) + :on-press (if keycard? + keycard-feature-unavailable + #(join-community-and-navigate-back id)) :container-style {:flex 1} :inner-style {:background-color (colors/resolve-color color theme)}} (i18n/label :t/request-to-join)]] diff --git a/src/status_im/contexts/communities/overview/view.cljs b/src/status_im/contexts/communities/overview/view.cljs index 9d6a88553d..8fb4275ed1 100644 --- a/src/status_im/contexts/communities/overview/view.cljs +++ b/src/status_im/contexts/communities/overview/view.cljs @@ -106,12 +106,14 @@ [quo/text (i18n/label :t/network-not-supported)]) (defn- request-access-button - [id color] + [id color keycard? keycard-feature-unavailable] [quo/button - {:on-press (if config/community-accounts-selection-enabled? - #(rf/dispatch [:open-modal :community-account-selection-sheet - {:community-id id}]) - #(rf/dispatch [:open-modal :community-requests-to-join {:id id}])) + {:on-press (if keycard? + keycard-feature-unavailable + (if config/community-accounts-selection-enabled? + #(rf/dispatch [:open-modal :community-account-selection-sheet + {:community-id id}]) + #(rf/dispatch [:open-modal :community-requests-to-join {:id id}]))) :accessibility-label :show-request-to-join-screen-button :customization-color color :container-style {:margin-bottom 12} @@ -126,27 +128,33 @@ (defn- token-requirements [{:keys [id color role-permissions?]}] - (let [{:keys [can-request-access? no-member-permission? networks-not-supported? - highest-permission-role - tokens]} (rf/sub [:community/token-gated-overview id]) - highest-role-text (i18n/label - (communities.utils/role->translation-key highest-permission-role :t/member)) - on-press (rn/use-callback - (fn [] - (if config/community-accounts-selection-enabled? - (rf/dispatch [:open-modal :community-account-selection-sheet - {:community-id id}]) - (rf/dispatch [:open-modal :community-requests-to-join - {:id id}]))) - [id]) - on-press-info #(rf/dispatch - [:show-bottom-sheet {:content token-gated-communities-info}])] + (let + [{:keys [can-request-access? no-member-permission? networks-not-supported? + highest-permission-role + tokens]} (rf/sub [:community/token-gated-overview id]) + highest-role-text (i18n/label + (communities.utils/role->translation-key highest-permission-role + :t/member)) + on-press (rn/use-callback + (fn [] + (if config/community-accounts-selection-enabled? + (rf/dispatch [:open-modal :community-account-selection-sheet + {:community-id id}]) + (rf/dispatch [:open-modal :community-requests-to-join + {:id id}]))) + [id]) + on-press-info #(rf/dispatch + [:show-bottom-sheet {:content token-gated-communities-info}]) + keycard? (rf/sub [:keycard/keycard-profile?]) + keycard-feature-unavailable (rn/use-callback + #(rf/dispatch [:keycard/feature-unavailable-show]))] + (cond networks-not-supported? [network-not-supported] (or (not role-permissions?) no-member-permission?) - [request-access-button id color] + [request-access-button id color keycard? keycard-feature-unavailable] :else [quo/community-token-gating @@ -154,7 +162,7 @@ :tokens tokens :community-color color :satisfied? can-request-access? - :on-press on-press + :on-press (if keycard? keycard-feature-unavailable on-press) :on-press-info on-press-info}]))) (defn- join-community diff --git a/src/status_im/contexts/keycard/events.cljs b/src/status_im/contexts/keycard/events.cljs index 4ad871b8c0..5d894b7f0d 100644 --- a/src/status_im/contexts/keycard/events.cljs +++ b/src/status_im/contexts/keycard/events.cljs @@ -9,7 +9,9 @@ status-im.contexts.keycard.pin.events status-im.contexts.keycard.sign.events [status-im.contexts.keycard.utils :as keycard.utils] - utils.datetime)) + [utils.address :as address] + utils.datetime + [utils.ethereum.eip.eip55 :as eip55])) (rf/reg-event-fx :keycard/on-card-connected (fn [{:keys [db]} _] @@ -65,6 +67,30 @@ (fn [_ [data]] {:effects.keycard/export-key data})) +(rf/reg-event-fx :keycard/connect-derive-address-and-add-account + (fn [_ [{:keys [pin derivation-path key-uid account-preferences]}]] + {:fx [[:dispatch + [:keycard/connect + {:key-uid key-uid + :on-success + (fn [] + (rf/dispatch + [:keycard/export-key + {:pin pin + :path derivation-path + :on-success (fn [public-key] + (let [derived-account {:public-key (str "0x" public-key) + :address (eip55/address->checksum + (str "0x" + (address/public-key->address + (subs public-key 2)))) + :path derivation-path}] + (rf/dispatch [:keycard/disconnect]) + (rf/dispatch [:wallet/add-account + (assoc account-preferences :key-uid key-uid) + derived-account]))) + :on-failure #(rf/dispatch [:keycard/on-action-with-pin-error %])}]))}]]]})) + (rf/reg-event-fx :keycard/cancel-connection (fn [{:keys [db]}] {:db (update db diff --git a/src/status_im/contexts/keycard/feature_unavailable/events.cljs b/src/status_im/contexts/keycard/feature_unavailable/events.cljs index 091c60348c..48dc7752b8 100644 --- a/src/status_im/contexts/keycard/feature_unavailable/events.cljs +++ b/src/status_im/contexts/keycard/feature_unavailable/events.cljs @@ -5,5 +5,8 @@ (rf/reg-event-fx :keycard/feature-unavailable-show - (fn [_] - {:fx [[:dispatch [:show-bottom-sheet {:content feature-unavailable/view}]]]})) + (fn [_ [options]] + {:fx [[:dispatch + [:show-bottom-sheet + {:theme (:theme options) + :content feature-unavailable/view}]]]})) diff --git a/src/status_im/contexts/profile/settings/screens/password/view.cljs b/src/status_im/contexts/profile/settings/screens/password/view.cljs index 499e788e45..6988dc52c5 100644 --- a/src/status_im/contexts/profile/settings/screens/password/view.cljs +++ b/src/status_im/contexts/profile/settings/screens/password/view.cljs @@ -7,33 +7,37 @@ [utils.re-frame :as rf])) (defn- on-press-biometric-enable - [button-label theme] + [button-label theme keycard-profile?] (fn [] - (rf/dispatch - [:standard-auth/authorize-with-password - {:blur? true - :theme theme - :auth-button-label (i18n/label :t/biometric-enable-button {:bio-type-label button-label}) - :on-auth-success (fn [password] - (rf/dispatch [:hide-bottom-sheet]) - (rf/dispatch - [:biometric/authenticate - {:on-success #(rf/dispatch [:biometric/enable password]) - :on-fail #(rf/dispatch [:biometric/show-message (ex-cause %)])}]))}]))) + (if keycard-profile? + (rf/dispatch [:keycard/feature-unavailable-show {:theme :dark}]) + (rf/dispatch + [:standard-auth/authorize-with-password + {:blur? true + :theme theme + :auth-button-label (i18n/label :t/biometric-enable-button {:bio-type-label button-label}) + :on-auth-success (fn [password] + (rf/dispatch [:hide-bottom-sheet]) + (rf/dispatch + [:biometric/authenticate + {:on-success #(rf/dispatch [:biometric/enable password]) + :on-fail #(rf/dispatch [:biometric/show-message + (ex-cause %)])}]))}])))) (defn- get-biometric-item [theme] - (let [auth-method (rf/sub [:auth-method]) - biometric-type (rf/sub [:biometrics/supported-type]) - label (biometric/get-label-by-type biometric-type) - icon (biometric/get-icon-by-type biometric-type) - supported? (boolean biometric-type) - enabled? (= auth-method constants/auth-method-biometric) - biometric-on? (and supported? enabled?) - press-handler (when supported? - (if biometric-on? - (fn [] (rf/dispatch [:biometric/disable])) - (on-press-biometric-enable label theme)))] + (let [auth-method (rf/sub [:auth-method]) + biometric-type (rf/sub [:biometrics/supported-type]) + keycard-profile? (rf/sub [:keycard/keycard-profile?]) + label (biometric/get-label-by-type biometric-type) + icon (biometric/get-icon-by-type biometric-type) + supported? (boolean biometric-type) + enabled? (= auth-method constants/auth-method-biometric) + biometric-on? (and supported? enabled?) + press-handler (when supported? + (if biometric-on? + (fn [] (rf/dispatch [:biometric/disable])) + (on-press-biometric-enable label theme keycard-profile?)))] {:title label :image-props icon :image :icon @@ -58,7 +62,8 @@ (defn view [] - (let [theme (quo.theme/use-theme)] + (let [theme (quo.theme/use-theme) + keycard-profile? (rf/sub [:keycard/keycard-profile?])] [quo/overlay {:type :shell :top-inset? true} [quo/page-nav {:background :blur @@ -68,6 +73,7 @@ [quo/category {:key :category :data [(get-biometric-item theme) - (get-change-password-item)] + (when-not keycard-profile? + (get-change-password-item))] :blur? true :list-type :settings}]])) diff --git a/src/status_im/contexts/settings/wallet/keypairs_and_accounts/view.cljs b/src/status_im/contexts/settings/wallet/keypairs_and_accounts/view.cljs index 97a159a2f7..4dbf020cb0 100644 --- a/src/status_im/contexts/settings/wallet/keypairs_and_accounts/view.cljs +++ b/src/status_im/contexts/settings/wallet/keypairs_and_accounts/view.cljs @@ -41,7 +41,7 @@ (defn- keypair [{keypair-type :type - :keys [accounts name] + :keys [accounts name keycard?] :as item} _ _ {:keys [profile-picture compressed-key customization-color]}] @@ -59,7 +59,7 @@ :type (if default-keypair? :default-keypair :keypair) - :stored :on-device + :stored (if keycard? :on-keycard :on-device) :shortened-key shortened-key :customization-color customization-color :profile-picture profile-picture})})) @@ -68,7 +68,7 @@ [quo/keypair {:blur? true :status-indicator false - :stored :on-device + :stored (if keycard? :on-keycard :on-device) :action (if default-keypair? :none :options) :accounts accounts :customization-color customization-color diff --git a/src/status_im/contexts/syncing/syncing_devices_list/view.cljs b/src/status_im/contexts/syncing/syncing_devices_list/view.cljs index 59c29df88e..74fb9219d4 100644 --- a/src/status_im/contexts/syncing/syncing_devices_list/view.cljs +++ b/src/status_im/contexts/syncing/syncing_devices_list/view.cljs @@ -38,7 +38,11 @@ #(if (:enabled? %) :paired-devices :unpaired-devices) - other-devices)] + other-devices) + keycard? (rf/sub [:keycard/keycard-profile?]) + keycard-feature-unavailable (rn/use-callback + #(rf/dispatch [:keycard/feature-unavailable-show + {:theme :dark}]))] [quo/overlay {:type :shell :top-inset? true} [quo/page-nav {:type :no-title @@ -60,7 +64,9 @@ :type :primary :customization-color profile-color :icon-only? true - :on-press open-setup-syncing-with-customization-color} + :on-press (if keycard? + keycard-feature-unavailable + open-setup-syncing-with-customization-color)} :i/add]] [device/view (merge user-device {:this-device? true})] (when (seq paired-devices) diff --git a/src/status_im/contexts/wallet/account/tabs/about/view.cljs b/src/status_im/contexts/wallet/account/tabs/about/view.cljs index 5996b9ee3e..b5c3adb09c 100644 --- a/src/status_im/contexts/wallet/account/tabs/about/view.cljs +++ b/src/status_im/contexts/wallet/account/tabs/about/view.cljs @@ -69,7 +69,9 @@ (let [{:keys [customization-color] :as profile} (rf/sub [:profile/profile-with-image]) {:keys [address path watch-only?]} (rf/sub [:wallet/current-viewing-account]) {keypair-name :name - keypair-type :type} (rf/sub [:wallet/current-viewing-account-keypair]) + keypair-type :type + keycards :keycards} (rf/sub [:wallet/current-viewing-account-keypair]) + keypair-keycard? (boolean (seq keycards)) networks (rf/sub [:wallet/network-preference-details]) origin-type (case keypair-type :seed @@ -98,7 +100,7 @@ (when (not watch-only?) [quo/account-origin {:type origin-type - :stored :on-device + :stored (if keypair-keycard? :on-keycard :on-device) :profile-picture (profile.utils/photo profile) :customization-color customization-color :derivation-path path diff --git a/src/status_im/contexts/wallet/add_account/create_account/select_keypair/view.cljs b/src/status_im/contexts/wallet/add_account/create_account/select_keypair/view.cljs index fd9c32fbdc..4a0525a437 100644 --- a/src/status_im/contexts/wallet/add_account/create_account/select_keypair/view.cljs +++ b/src/status_im/contexts/wallet/add_account/create_account/select_keypair/view.cljs @@ -58,13 +58,14 @@ [item _ _ {:keys [profile-picture compressed-key selected-key-uid set-selected-key-uid customization-color]}] (let [profile-keypair? (= (:type item) :profile) + keycard? (boolean (seq (:keycards item))) accounts (parse-accounts (:accounts item))] [quo/keypair {:customization-color customization-color :profile-picture (when profile-keypair? profile-picture) :status-indicator false :type (if profile-keypair? :default-keypair :other) - :stored :on-device + :stored (if keycard? :on-keycard :on-device) :on-options-press #(js/alert "Options pressed") :action :selector :blur? false diff --git a/src/status_im/contexts/wallet/add_account/create_account/view.cljs b/src/status_im/contexts/wallet/add_account/create_account/view.cljs index 4fca1cca93..8c0ab7472d 100644 --- a/src/status_im/contexts/wallet/add_account/create_account/view.cljs +++ b/src/status_im/contexts/wallet/add_account/create_account/view.cljs @@ -22,7 +22,7 @@ [utils.string])) (defn- get-keypair-data - [{:keys [title primary-keypair? new-keypair? derivation-path customization-color]}] + [{:keys [title primary-keypair? new-keypair? derivation-path customization-color keycard?]}] [{:title title :image (if primary-keypair? :avatar :icon) :image-props (if primary-keypair? @@ -35,7 +35,7 @@ :button-text (i18n/label :t/edit) :alignment :flex-start} :description :text - :description-props {:text (i18n/label :t/on-device)}} + :description-props {:text (i18n/label (if keycard? :on-keycard :on-device))}} (when-not (string/blank? derivation-path) (let [formatted-path (string/replace derivation-path #"/" " / ") on-auth-success (fn [password] @@ -123,7 +123,7 @@ :container-style color-picker-style}]])]))) (defn- new-account-origin - [{:keys [keypair-title derivation-path customization-color]}] + [{:keys [keypair-title derivation-path customization-color keycard?]}] (let [{keypair-name :name} (rf/sub [:wallet/selected-keypair]) primary? (rf/sub [:wallet/selected-primary-keypair?]) keypair-name (or keypair-title @@ -135,7 +135,8 @@ [quo/category {:list-type :settings :label (i18n/label :t/origin) - :data (get-keypair-data {:primary-keypair? primary? + :data (get-keypair-data {:keycard? keycard? + :primary-keypair? primary? :title keypair-name :derivation-path derivation-path :customization-color customization-color})}]])) @@ -229,20 +230,37 @@ set-derivation-path #(reset! derivation-path %)] (fn [{:keys [on-change-text set-account-color set-emoji customization-color error]}] (let [{:keys [derived-from - key-uid]} (rf/sub [:wallet/selected-keypair]) - on-auth-success (rn/use-callback - (fn [password] - (let [preferences {:account-name @account-name - :color @account-color - :emoji @emoji}] - (rf/dispatch - [:wallet/derive-address-and-add-account - {:password password - :derived-from-address derived-from - :key-uid key-uid - :derivation-path @derivation-path - :account-preferences preferences}]))) - [derived-from])] + key-uid keycards]} (rf/sub [:wallet/selected-keypair]) + keycard? (boolean (seq keycards)) + on-auth-success (rn/use-callback + (fn [password] + (let [preferences {:account-name @account-name + :color @account-color + :emoji @emoji}] + (rf/dispatch + [:wallet/derive-address-and-add-account + {:password password + :derived-from-address derived-from + :key-uid key-uid + :derivation-path @derivation-path + :account-preferences preferences}]))) + [derived-from]) + on-complete (rn/use-callback + (fn [] + (let [preferences {:account-name @account-name + :color @account-color + :emoji @emoji}] + (rf/dispatch + [:standard-auth/authorize-with-keycard + {:on-complete + #(rf/dispatch + [:keycard/connect-derive-address-and-add-account + {:pin % + :derived-from-address derived-from + :key-uid key-uid + :derivation-path @derivation-path + :account-preferences preferences}])}]))) + [derived-from])] (rn/use-effect #(rf/dispatch [:wallet/next-derivation-path @@ -252,10 +270,13 @@ [floating-button {:account-color @account-color - :slide-button-props {:on-auth-success on-auth-success - :disabled? (or (empty? @account-name) - (string/blank? @derivation-path) - (some? error))}} + :slide-button-props {:on-auth-success (when-not keycard? on-auth-success) + :on-complete + (when keycard? on-complete) + :disabled? + (or (empty? @account-name) + (string/blank? @derivation-path) + (some? error))}} [avatar {:account-color @account-color :emoji @emoji @@ -269,7 +290,8 @@ {:account-color @account-color :set-account-color set-account-color}] [new-account-origin - {:derivation-path @derivation-path + {:keycard? keycard? + :derivation-path @derivation-path :customization-color customization-color}]])))) (defn view diff --git a/src/status_im/contexts/wallet/events.cljs b/src/status_im/contexts/wallet/events.cljs index 6f69066ba6..eba0f274a9 100644 --- a/src/status_im/contexts/wallet/events.cljs +++ b/src/status_im/contexts/wallet/events.cljs @@ -307,9 +307,8 @@ (rf/reg-event-fx :wallet/add-account (fn [_ - [{:keys [key-uid password account-name emoji color type] - :or {type :generated}} - {:keys [public-key address path] :as _derived-account}]] + [{:keys [key-uid password account-name emoji color type] :or {type :generated}} + {:keys [public-key address path]}]] (let [lowercase-address (some-> address string/lower-case) account-config {:key-uid (when (= type :generated) key-uid) diff --git a/src/status_im/contexts/wallet/send/transaction_confirmation/view.cljs b/src/status_im/contexts/wallet/send/transaction_confirmation/view.cljs index efd93650f3..6401225091 100644 --- a/src/status_im/contexts/wallet/send/transaction_confirmation/view.cljs +++ b/src/status_im/contexts/wallet/send/transaction_confirmation/view.cljs @@ -248,7 +248,9 @@ account))} user-props {:full-name to-address :address (utils/get-shortened-address - to-address)}] + to-address)} + sign-on-keycard? (get-in transaction-for-signing + [:signingDetails :signOnKeycard])] ;; In token send flow we already have transaction built when ;; we reach confirmation screen. But in send collectible flow ;; routes request happens at the same time with navigation to @@ -279,20 +281,24 @@ :transaction-type transaction-type}] (when (and (not loading-suggested-routes?) route (seq route)) [standard-auth/slide-button - {:keycard-supported? true - :size :size-48 + {:size :size-48 :track-text (if (= transaction-type :tx/bridge) (i18n/label :t/slide-to-bridge) (i18n/label :t/slide-to-send)) :container-style {:z-index 2} :disabled? (not transaction-for-signing) :customization-color account-color + :auth-button-label (i18n/label :t/confirm) + :on-complete (when sign-on-keycard? + #(rf/dispatch + [:wallet/prepare-signatures-for-transactions + :send + ""])) :on-auth-success - (fn [data] + (fn [psw] (rf/dispatch - [:wallet/prepare-signatures-for-transactions - :send data])) - :auth-button-label (i18n/label :t/confirm)}])] + [:wallet/prepare-signatures-for-transactions :send + psw]))}])] :gradient-cover? true :customization-color (:color account)} [rn/view diff --git a/src/status_im/contexts/wallet/swap/set_spending_cap/view.cljs b/src/status_im/contexts/wallet/swap/set_spending_cap/view.cljs index 33fe5e81aa..7eae016dc7 100644 --- a/src/status_im/contexts/wallet/swap/set_spending_cap/view.cljs +++ b/src/status_im/contexts/wallet/swap/set_spending_cap/view.cljs @@ -217,18 +217,23 @@ (defn- slide-button [] - (let [loading-swap-proposal? (rf/sub [:wallet/swap-loading-swap-proposal?]) - swap-proposal (rf/sub [:wallet/swap-proposal-without-fees]) - account (rf/sub [:wallet/current-viewing-account]) - on-auth-success (rn/use-callback - #(rf/dispatch [:wallet/prepare-signatures-for-transactions :swap %]))] + (let [loading-swap-proposal? (rf/sub [:wallet/swap-loading-swap-proposal?]) + swap-proposal (rf/sub [:wallet/swap-proposal-without-fees]) + account (rf/sub [:wallet/current-viewing-account]) + transaction-for-signing (rf/sub [:wallet/swap-transaction-for-signing]) + sign-on-keycard? (get-in transaction-for-signing + [:signingDetails :signOnKeycard]) + on-auth-success (rn/use-callback + #(rf/dispatch [:wallet/prepare-signatures-for-transactions :swap %])) + on-complete (rn/use-callback + #(rf/dispatch [:wallet/prepare-signatures-for-transactions :swap ""]))] [standard-auth/slide-button {:size :size-48 :track-text (i18n/label :t/slide-to-sign) :container-style {:z-index 2} :customization-color (:color account) :disabled? (or loading-swap-proposal? (not swap-proposal)) - :keycard-supported? true + :on-complete (when sign-on-keycard? on-complete) :on-auth-success on-auth-success :auth-button-label (i18n/label :t/confirm)}])) diff --git a/src/status_im/contexts/wallet/swap/swap_confirmation/view.cljs b/src/status_im/contexts/wallet/swap/swap_confirmation/view.cljs index 80706a124a..be4089a4db 100644 --- a/src/status_im/contexts/wallet/swap/swap_confirmation/view.cljs +++ b/src/status_im/contexts/wallet/swap/swap_confirmation/view.cljs @@ -168,7 +168,9 @@ transaction-for-signing (rf/sub [:wallet/swap-transaction-for-signing]) swap-proposal (rf/sub [:wallet/swap-proposal-without-fees]) account (rf/sub [:wallet/current-viewing-account]) - account-color (:color account)] + account-color (:color account) + sign-on-keycard? (get-in transaction-for-signing + [:signingDetails :signOnKeycard])] [standard-auth/slide-button {:size :size-48 :track-text (i18n/label :t/slide-to-swap) @@ -178,7 +180,11 @@ (not swap-proposal) (not transaction-for-signing)) :auth-button-label (i18n/label :t/confirm) - :keycard-supported? true + :on-complete (when sign-on-keycard? + #(rf/dispatch + [:wallet/prepare-signatures-for-transactions + :swap + ""])) :on-auth-success (fn [data] (rf/dispatch [:wallet/stop-get-swap-proposal]) (rf/dispatch [:wallet/prepare-signatures-for-transactions :swap data]))}])) diff --git a/src/status_im/subs/wallet/wallet.cljs b/src/status_im/subs/wallet/wallet.cljs index 2b56325af5..f9f40ea689 100644 --- a/src/status_im/subs/wallet/wallet.cljs +++ b/src/status_im/subs/wallet/wallet.cljs @@ -349,12 +349,13 @@ :<- [:wallet/keypairs-list] (fn [keypairs [_ format-options]] (reduce - (fn [acc {:keys [accounts name type key-uid lowest-operability]}] + (fn [acc {:keys [accounts name type key-uid lowest-operability keycards]}] (if (= lowest-operability :no) (update acc :missing conj {:type type + :keycard? (boolean (seq keycards)) :name name :key-uid key-uid :accounts (format-settings-missing-keypair-accounts accounts)}) @@ -362,6 +363,7 @@ :operable conj {:type type + :keycard? (boolean (seq keycards)) :name name :key-uid key-uid :accounts (format-settings-keypair-accounts accounts format-options)}))) diff --git a/src/utils/address.cljs b/src/utils/address.cljs index 7c3535f42e..a51a627f6a 100644 --- a/src/utils/address.cljs +++ b/src/utils/address.cljs @@ -141,3 +141,14 @@ (defn zero-address? [address] (= address zero-address)) + +(defn public-key->address + [public-key] + (let [length (count public-key) + normalized-key (case length + 132 (str "0x" (subs public-key 4)) + 130 public-key + 128 (str "0x" public-key) + nil)] + (when normalized-key + (subs (native-module/sha3 normalized-key) 26))))