From 74e84644aa2af714abfc73ec2b9475b1448d29e2 Mon Sep 17 00:00:00 2001 From: Omar Basem Date: Mon, 8 Apr 2024 17:53:41 +0400 Subject: [PATCH] Wallet: Derivation Path - Scanning for Activity (#19482) Wallet: Derivation Path - Scanning for Activity (#19482) --- resources/images/icons2/12x12/face-id@2x.png | Bin 0 -> 750 bytes resources/images/icons2/12x12/face-id@3x.png | Bin 0 -> 1125 bytes resources/images/icons2/16x16/scanning@2x.png | Bin 0 -> 595 bytes resources/images/icons2/16x16/scanning@3x.png | Bin 0 -> 889 bytes .../wallet/add_address_to_watch/view.cljs | 2 +- .../edit_derivation_path/component_spec.cljs | 36 ---- .../edit_derivation_path/style.cljs | 14 +- .../edit_derivation_path/view.cljs | 162 +++++++++--------- .../wallet/create_account/events.cljs | 26 ++- .../wallet/create_account/events_test.cljs | 11 ++ .../contexts/wallet/create_account/view.cljs | 57 +++--- src/status_im/core_spec.cljs | 1 - src/status_im/subs/wallet/wallet.cljs | 5 + translations/en.json | 3 +- 14 files changed, 167 insertions(+), 150 deletions(-) create mode 100644 resources/images/icons2/12x12/face-id@2x.png create mode 100644 resources/images/icons2/12x12/face-id@3x.png create mode 100644 resources/images/icons2/16x16/scanning@2x.png create mode 100644 resources/images/icons2/16x16/scanning@3x.png delete mode 100644 src/status_im/contexts/wallet/create_account/edit_derivation_path/component_spec.cljs diff --git a/resources/images/icons2/12x12/face-id@2x.png b/resources/images/icons2/12x12/face-id@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..f9b5d8023b434dc93a223b0068fe7bd81d16c5e3 GIT binary patch literal 750 zcmVP#7Q=JoeE`r22bQ4B z>bJbvv~7j{Pb6YARxC?^2`ai>4gI7Az9tF-!S(D&3@6gBMFAUVA-=QAg>@sDOB8eR7pZ1Xc)WO^WQHo4=ywu@d>!a~Ht)S)l0XHT{r^zo@F+-FR$&}}ZPgD~A5H%;;Q=3mNGx)wI+cn0B1 z+2U7v)Nve&Pg{q3QkR2$^f(-t9_1j1TZ!e-ObrOQtYY{z+mTya zhkW)|{`kC028%qW?;0Sn8*XX(j>Tx!R-h^Gnr_+~bU=!S3b*vn?J;ccYETVBgiko- zYXZR&F`Cmr(Q_hR%xRB!7}V0&DGm4;N@@oP$X9lcO?}}40_{)<<@4Ej^TO> z*WHLp_|wO;xv$~+q7KFP-gV&wpppV1r0c?Y0_C^>7Vo-nf=Z#tqzt3yD{dXU0s~h1 zJ*IEYLH*3LUmM@S(`ayp^YDdazyTWtg?M)A2h+Hd9pjYhKzObUj1$uK-OEf;2Vxqo gDCb$nrGIex5AWO`Qx$DQ%K!iX07*qoM6N<$f*%-BXaE2J literal 0 HcmV?d00001 diff --git a/resources/images/icons2/12x12/face-id@3x.png b/resources/images/icons2/12x12/face-id@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..99f905cf106d33bb3dba88edd1f9dbe4e92086c7 GIT binary patch literal 1125 zcmV-r1e*JaP)K}-iwfkOq*0Z;)>1rZhC4x$;tH)4jDiKOKoJ*>5) zjS_5_d~j!+=yCV%@!k74*T5|kbzMcReSL{bUoOWfdfLF7|BS-0O?Rk$-$Oj@K`jhS z^fkH&a82o>1H=;P6i5%3h$j{Pl%IwC3EPdvege#5nCyN>@AF^aLA_1T3tV4>;<;Yz z>iyXg$+>L&Qf?>MTqY^ZYlY;DwsBoR^oo3=Gx=^OfYHq*Dw5}6PmaQ6)Sw@UFBgut zK5YxA58SI^z5alTvS3_$90>N)tK!Bb1MQD{NXD|!p@2E6+x-z;Ja#UoE5$pe{1Dtw z?@zELVX*J$(Rpo;6I(~w$~<4Xw0ITXMek7*g%P$WJf>fW&#Y63?xO#&+{cQcWKw}) z9P}P<8%(yl*pwW7Zev{Ha$4T304bPbOR15Xg}Xn~<$L48 zwOKFf8z{uj@~op5)f64lr7s23-eXc`Tn6Y~BXHA2a|5L-W9mLS0d?sQ0{gD$0y&`6 zT1@#CeR9;0?MWUI%8F4hJJzCg82gM{!5FI$O1yn3uXpw6s9LWU-=mN7tMu0;6`kA} zrbws^P>TK=AP#t)NR@2|)PE&qfx)MxAHA|(9Z3ow=Nm)pVBVp>5)XqX3E~1!Kg2df zJoKh2a--MSP(0i+`46Z|whBlxWxA&ija-At$m*s zttM+70~u$Q)=MEw)Knaxlz;nse11^qssqAD8KNGbsreX+{FG7-BGYtt3NIM--NTwt)Oo$uqP{b$*7fF{l(~1)8JtT-)R z9WYs-@?F0T&^AZtwm5S(SE&mp3^obar&ucqe=LD)_gpgXA#J;quKj}*g{8pDJY&Y> r;axviN%fWPKUnNZ;rts@@IR5?nD*H9MF4K@00000NkvXXu0mjfs;2{D literal 0 HcmV?d00001 diff --git a/resources/images/icons2/16x16/scanning@2x.png b/resources/images/icons2/16x16/scanning@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..509b02716a88b35cc716c9301c3583b04fb3d6b4 GIT binary patch literal 595 zcmV-Z0<8UsP)ok z!Y~wlDLRxvXR;TadIGqCW#=u#6QDQH6NpP!$`L#Puyct^ch$jt7@Yw}oA}cPY>~_$ zbbuLoGijTjDp0Z(YoQZI|~Q zs3&4Eq^d`S0%6D7?rxuaJfx^4D=zmuhOkAEdz!U^Ivt8$8w()q6C#hTLm>h&YIoAz zL*I0SLaw^#gM1i!;EIw=mM$wb;5!u7|WM$Y1 zFi&4)^a^DQ+6I%ragZCV4aVod4lnswBHqm_zBMw0Knu%76ug5KW4r=%Zdb9vzlRnQ zx)k|-4H<)U#@Wb!(mwey3e3HN%ptw_uGNu+0D}{KFeFe$_Aow`oqz)Cm`C5u@MP4g zNc)T@WKAo9Je)gPhe$3luv;^5A?PDMmSmCFKr7^A`!AKNlZ7_nDq$i~%DNKlc_3aI zm;pt;SEJa#CfNC+;QuHzfQL}~@}7is zeW=1!ut5URSL$1tKEi*8?x!H|16{sjZe;K!tGt-J1oQJ_E6;ErFTv~z$w;S2XGx2Q zN#1AxuQqB~qI-jy;n7yhv8Gc>(NF9u_g)=eUT58>r&JAjIoIWK2Jo_(t&xvtjE>rO z>Oiv+dPS@_DTci56b->EUABf-Dy=5}n#>6GVEJeWUZ&NuH25Pc{}Q|M4M79*KZXAT za%AI8O>?uMrKROaWHxgYP(0xk!27cFUSCFCyfP{yvi}`@1U$5~w6xSoE-SH0CT(JZ z=U_fUgV1(*l-|clc$-bH7*dOJ$mzbcL~-bSQ!xRjSR}%Kx~!d+r^*;Y%4`_-C&`62 zgGC9iY)w9($r;eai5AAi4jLlTVqp5X)rqYWz$Z%;L2-e`h%ljdoi=g?I0MFK0$Or+Lg~JndXl^0`Ya+v zaK7}TNnR8;)OSU4Hju;Pj9C}))S{fxp-U`%EGMFsE`)H3((3}^s^}Q2^o)#*7zxEE z6f`j2*V(a?k`?XK^YNmj{nCJjUu5ff2vIx2Umt9Y%A_hIG9EgffAnK>y4%B1NtSOu zAs7-e?$)SJ^3KhDNIXCOEG@|vaBn+IEP^g P00000NkvXXu0mjfif) (reveal-action) -> show | -> (clear-action) -> empty -> (derive-action) -> choose -> (choose-action) -> show" - [{:keys [on-reset on-reveal]}] - (let [top (safe-area/get-top) - bottom (safe-area/get-bottom) - state (reagent/atom :default) - reveal-action (fn [_] - (reset! state :show) - (when on-reveal - (on-reveal))) - clear-action #(reset! state :empty) - derive-action #(js/alert "To be implemented") - choose-action #(reset! state :show) - path-value (reagent/atom (utils/get-formatted-derivation-path 3)) - handle-path-change (fn [v] - (reset! path-value v) - (when (empty? v) - (clear-action))) - reset-path-value (fn [_] - (reset! path-value "") - (clear-action) - (when on-reset - (on-reset)))] + [{:keys [on-reset]}] + (let [top (safe-area/get-top) + bottom (safe-area/get-bottom) + input-focused? (reagent/atom false) + path-value (reagent/atom "") + input-ref (reagent/atom nil) + reset-path-value (fn [_] + (reset! path-value "") + (when on-reset + (on-reset)))] (fn [{:keys [theme]}] - (let [{:keys [public-key]} (rf/sub [:profile/profile]) - primary-name (first (rf/sub [:contacts/contact-two-names-by-identity - public-key])) - profile-picture (rf/sub [:profile/image]) - show-path-format-sheet #(rf/dispatch [:show-bottom-sheet {:content path-format-sheet/view}])] + (let [{:keys [public-key address]} (rf/sub [:profile/profile]) + {:keys [password current-derivation-path]} (rf/sub [:get-screen-params]) + primary-name (first (rf/sub + [:contacts/contact-two-names-by-identity + public-key])) + profile-picture (rf/sub [:profile/image]) + show-path-format-sheet #(rf/dispatch [:show-bottom-sheet + {:content path-format-sheet/view}]) + derivation-path (rf/sub [:wallet/derivation-path]) + state (rf/sub [:wallet/derivation-path-state]) + navigate-back-handler #(if @input-focused? + (do + (.blur ^js @input-ref) + true) + (rf/dispatch [:navigate-to + :screen/wallet.create-account])) + on-change-text #(rf/dispatch + [:wallet/get-derived-addresses + {:password (security/safe-unmask-data + password) + :paths [(string/replace @path-value + #"\s" + "")] + :derived-from address}])] + (rn/use-mount (fn [] + (reset! path-value current-derivation-path) + (rf/dispatch [:wallet/get-derived-addresses + {:password (security/safe-unmask-data password) + :paths [(string/replace @path-value #"\s" "")] + :derived-from address}]) + (rn/hw-back-add-listener navigate-back-handler) + #(rn/hw-back-remove-listener navigate-back-handler))) [rn/view {:style (style/screen top)} [quo/page-nav @@ -82,54 +99,33 @@ :value (i18n/label :t/default-format) :container-style {:margin-horizontal 20}}]] [quo/input - {:container-style style/input-container - :value @path-value - :editable false - :label (i18n/label :t/derivation-path) - :placeholder (utils/get-formatted-derivation-path 3) - :button {:on-press reset-path-value - :text (i18n/label :t/reset)} - :on-change-text handle-path-change}] - - (case @state - :default - [quo/bottom-actions - {:actions :one-action - :button-one-label (i18n/label :t/reveal-address) - :button-one-props {:type :outline - :icon-left :i/keycard-card - :on-press reveal-action}}] - - :empty - [quo/bottom-actions - {:actions :one-action - :button-one-label (i18n/label :t/derive-addresses) - :button-one-props {:type :outline - :icon-left :i/keycard-card - :on-press derive-action}}] - - :show - [rn/view {:style style/revealed-address-container} - [rn/view {:style (style/revealed-address theme)} - [quo/text - {:weight :monospace} - temp/address]] - [quo/info-message - {:type :success - :icon :i/done - :style style/info} - (i18n/label :t/address-activity)]] - - :choose - [rn/view {:style style/temporal-placeholder} - [quo/text "Dropdown input will be here"] - [quo/button - {:on-press (fn [_] - (reset! path-value (utils/get-formatted-derivation-path 1)) - (choose-action))} - "Choose"]] - nil) - + {:ref #(reset! input-ref %) + :container-style style/input-container + :value @path-value + :on-focus #(reset! input-focused? true) + :on-blur #(reset! input-focused? false) + :show-soft-input-on-focus false + :editable true + :label (i18n/label :t/derivation-path) + :placeholder (utils/get-formatted-derivation-path 3) + :button {:on-press reset-path-value + :text (i18n/label :t/reset)}}] + [rn/view {:style style/revealed-address-container} + [rn/view {:style (style/revealed-address state theme)} + [quo/text + {:weight :monospace} + (:address derivation-path)]] + [quo/info-message + {:type (case state + :has-activity :success + :no-activity :warning + :default) + :icon (if (= state :scanning) :i/scanning :i/done) + :style style/info} + (i18n/label (case state + :has-activity :t/address-activity + :no-activity :t/address-no-activity + :t/scanning))]] [rn/view {:style (style/save-button-container bottom)} [quo/bottom-actions {:actions :one-action @@ -137,9 +133,17 @@ :button-one-props {:type :primary :on-press #(js/alert "Save!") :disabled? true}}]] - (when-not (= @state :show) + (when @input-focused? [quo/numbered-keyboard - {:left-action :dot - :delete-key? true}])])))) + {:left-action :dot + :delete-key? true + :container-style (style/keyboard bottom) + :on-press (fn [value] + (reset! path-value (str @path-value value)) + (on-change-text)) + :on-delete (fn [] + (reset! path-value (subs @path-value 0 (dec (count @path-value)))) + (on-change-text))}])])))) (def view (quo.theme/with-theme view-internal)) + diff --git a/src/status_im/contexts/wallet/create_account/events.cljs b/src/status_im/contexts/wallet/create_account/events.cljs index 76982e2025..07ae02ae89 100644 --- a/src/status_im/contexts/wallet/create_account/events.cljs +++ b/src/status_im/contexts/wallet/create_account/events.cljs @@ -1,6 +1,8 @@ (ns status-im.contexts.wallet.create-account.events - (:require [status-im.contexts.wallet.data-store :as data-store] - [utils.re-frame :as rf])) + (:require [camel-snake-kebab.extras :as cske] + [status-im.contexts.wallet.data-store :as data-store] + [utils.re-frame :as rf] + [utils.transforms :as transforms])) (defn get-keypairs-success [{:keys [db]} [keypairs]] @@ -49,3 +51,23 @@ {:db (update-in db [:wallet :ui :create-account] dissoc :new-keypair)}) (rf/reg-event-fx :wallet/clear-new-keypair clear-new-keypair) + +(defn get-derived-addresses + [{:keys [db]} [{:keys [password derived-from paths]}]] + {:db (assoc-in db [:wallet :ui :create-account :derivation-path-state] :scanning) + :json-rpc/call [{:method "wallet_getDerivedAddresses" + :params [password derived-from paths] + :on-success [:wallet/get-derived-addresses-success]}]}) + +(rf/reg-event-fx :wallet/get-derived-addresses get-derived-addresses) + +(defn get-derived-addresses-success + [{:keys [db]} [response]] + (let [derived-address (first response)] + {:db (-> db + (assoc-in [:wallet :ui :create-account :derivation-path-state] + (if (:has-activity derived-address) :has-activity :no-activity)) + (assoc-in [:wallet :ui :create-account :derivation-path] + (cske/transform-keys transforms/->kebab-case-keyword derived-address)))})) + +(rf/reg-event-fx :wallet/get-derived-addresses-success get-derived-addresses-success) diff --git a/src/status_im/contexts/wallet/create_account/events_test.cljs b/src/status_im/contexts/wallet/create_account/events_test.cljs index f795c0c4ef..4ced4d4b38 100644 --- a/src/status_im/contexts/wallet/create_account/events_test.cljs +++ b/src/status_im/contexts/wallet/create_account/events_test.cljs @@ -42,3 +42,14 @@ expected-db {:wallet {:ui {:create-account {}}}} effects (events/clear-new-keypair {:db db})] (is (match? (:db effects) expected-db)))) + +(deftest get-derived-addresses-test + (let [db {} + password "test-password" + derived-from "test-derive-from" + paths ["path1"] + event-args [{:password password :derived-from derived-from :paths paths}] + expected-db (assoc-in db [:wallet :ui :create-account :derivation-path-state] :scanning) + effects (events/get-derived-addresses {:db db} event-args) + result-db (:db effects)] + (is (match? result-db expected-db)))) diff --git a/src/status_im/contexts/wallet/create_account/view.cljs b/src/status_im/contexts/wallet/create_account/view.cljs index 7d9b506d72..c03586d60c 100644 --- a/src/status_im/contexts/wallet/create_account/view.cljs +++ b/src/status_im/contexts/wallet/create_account/view.cljs @@ -15,6 +15,7 @@ [status-im.contexts.wallet.create-account.style :as style] [status-im.contexts.wallet.create-account.utils :as create-account.utils] [status-im.contexts.wallet.sheets.account-origin.view :as account-origin] + [status-im.feature-flags :as ff] [utils.i18n :as i18n] [utils.re-frame :as rf] [utils.responsiveness :as responsiveness] @@ -23,29 +24,39 @@ (defn- get-keypair-data [{:keys [title primary-keypair? new-keypair? derivation-path customization-color]}] - [{:title title - :image (if primary-keypair? :avatar :icon) - :image-props (if primary-keypair? - {:full-name (utils.string/get-initials title 1) - :size :xxs - :customization-color customization-color} - :i/seed) - :action (when-not new-keypair? :button) - :action-props {:on-press #(rf/dispatch [:navigate-to :screen/wallet.select-keypair]) - :button-text (i18n/label :t/edit) - :alignment :flex-start} - :description :text - :description-props {:text (i18n/label :t/on-device)}} - {:title (i18n/label :t/derivation-path) - :image :icon - :image-props :i/derivated-path - :action :button - :action-props {:on-press #(js/alert "Coming soon!") - :button-text (i18n/label :t/edit) - :icon-left :i/placeholder - :alignment :flex-start} - :description :text - :description-props {:text (string/replace derivation-path #"/" " / ")}}]) + (let [formatted-path (string/replace derivation-path #"/" " / ") + on-auth-success (fn [password] + (rf/dispatch [:navigate-to + :screen/wallet.edit-derivation-path + {:password password + :current-derivation-path formatted-path}]))] + [{:title title + :image (if primary-keypair? :avatar :icon) + :image-props (if primary-keypair? + {:full-name (utils.string/get-initials title 1) + :size :xxs + :customization-color customization-color} + :i/seed) + :action (when-not new-keypair? :button) + :action-props {:on-press #(rf/dispatch [:navigate-to :screen/wallet.select-keypair]) + :button-text (i18n/label :t/edit) + :alignment :flex-start} + :description :text + :description-props {:text (i18n/label :t/on-device)}} + {:title (i18n/label :t/derivation-path) + :image :icon + :image-props :i/derivated-path + :action :button + :action-props {:on-press #(if (ff/enabled? :ff/wallet.edit-derivation-path) + (rf/dispatch [:standard-auth/authorize + {:on-auth-success on-auth-success + :auth-button-label (i18n/label :t/continue)}]) + (js/alert "Coming soon!")) + :button-text (i18n/label :t/edit) + :icon-left :i/face-id + :alignment :flex-start} + :description :text + :description-props {:text formatted-path}}])) (defn- f-view [_] diff --git a/src/status_im/core_spec.cljs b/src/status_im/core_spec.cljs index 673095197d..866c783af3 100644 --- a/src/status_im/core_spec.cljs +++ b/src/status_im/core_spec.cljs @@ -6,5 +6,4 @@ [status-im.contexts.shell.share.wallet.component-spec] [status-im.contexts.wallet.add-address-to-watch.component-spec] [status-im.contexts.wallet.add-address-to-watch.confirm-address.component-spec] - [status-im.contexts.wallet.create-account.edit-derivation-path.component-spec] [status-im.contexts.wallet.send.input-amount.component-spec])) diff --git a/src/status_im/subs/wallet/wallet.cljs b/src/status_im/subs/wallet/wallet.cljs index 8a33e4931c..9a7a9833ef 100644 --- a/src/status_im/subs/wallet/wallet.cljs +++ b/src/status_im/subs/wallet/wallet.cljs @@ -137,6 +137,11 @@ :goerli-enabled? goerli-enabled?}) selected-networks)))) +(rf/reg-sub + :wallet/derivation-path-state + :<- [:wallet/create-account] + :-> :derivation-path-state) + (rf/reg-sub :wallet/accounts :<- [:wallet] diff --git a/translations/en.json b/translations/en.json index c67f0468b0..9e59f594ec 100644 --- a/translations/en.json +++ b/translations/en.json @@ -2458,6 +2458,8 @@ "edit-wallet-network-preferences-updated-message": "Account network preferences has been updated", "search-assets": "Search assets", "address-activity": "This address has activity", + "address-no-activity": "This address has no activity", + "scanning": "Scanning for activity...", "keypairs": "Keypairs", "keypairs-description": "Select keypair to derive your new account from", "confirm-account-origin": "Confirm account origin", @@ -2481,7 +2483,6 @@ "est-time": "Est. time", "user-gets": "{{name}} gets", "slide-to-send": "Slide to send", - "this-address-has-activity": "This address has activity", "generate-new-keypair": "Generate new keypair", "import-using-phrase": "Import using recovery phrase", "import-from-keycard": "Import from Keycard",