From 56492949f17c56fec5e57345fa5aafb3a583ede3 Mon Sep 17 00:00:00 2001 From: Jamie Caprani Date: Thu, 26 Oct 2023 10:45:33 +0200 Subject: [PATCH] feat (wallet): add ability to create new account (#17496) --- ios/Podfile.lock | 4 +- .../enter_password/view.cljs | 14 ++--- .../standard_auth/view.cljs | 19 ++++-- .../contexts/profile/login/events.cljs | 6 +- .../contexts/syncing/setup_syncing/view.cljs | 3 +- .../contexts/wallet/common/temp.cljs | 30 ---------- .../contexts/wallet/common/utils.cljs | 8 ++- .../contexts/wallet/create_account/view.cljs | 60 ++++++++++++++----- src/status_im2/contexts/wallet/events.cljs | 43 ++++++++++++- src/status_im2/subs/root.cljs | 1 + src/utils/re_frame.cljs | 2 + translations/en.json | 5 +- 12 files changed, 128 insertions(+), 67 deletions(-) diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 5b9ddba5b7..d1af6b5224 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -765,7 +765,7 @@ SPEC CHECKSUMS: RNLanguages: 962e562af0d34ab1958d89bcfdb64fafc37c513e RNPermissions: ad71dd4f767ec254f2cd57592fbee02afee75467 RNReactNativeHapticFeedback: 2566b468cc8d0e7bb2f84b23adc0f4614594d071 - RNReanimated: b2dc21e263319892469d656dc58fc26fb03eadab + RNReanimated: 62e43ee6baafb9ba3d3af1857d7fd23a1d41bff0 RNShare: d82e10f6b7677f4b0048c23709bd04098d5aee6c RNStaticSafeAreaInsets: 055ddbf5e476321720457cdaeec0ff2ba40ec1b8 RNSVG: 80584470ff1ffc7994923ea135a3e5ad825546b9 @@ -777,6 +777,6 @@ SPEC CHECKSUMS: TouchID: ba4c656d849cceabc2e4eef722dea5e55959ecf4 Yoga: d24d6184b6b85f742536bd93bd07d69d7b9bb4c1 -PODFILE CHECKSUM: 6a5f0e6776ce4ef6193032d077947117ace77a87 +PODFILE CHECKSUM: 84b749023e1c988c133d7a6ec09d125536e4a4fd COCOAPODS: 1.12.0 diff --git a/src/status_im2/common/standard_authentication/enter_password/view.cljs b/src/status_im2/common/standard_authentication/enter_password/view.cljs index 5754ae912e..a49360790b 100644 --- a/src/status_im2/common/standard_authentication/enter_password/view.cljs +++ b/src/status_im2/common/standard_authentication/enter_password/view.cljs @@ -9,13 +9,11 @@ [utils.re-frame :as rf])) (defn view - [{:keys [on-enter-password button-label]}] - (let [{:keys [key-uid display-name - customization-color] - :as account} (rf/sub [:profile/multiaccount]) - {:keys [error processing password]} (rf/sub [:profile/login]) - sign-in-enabled? (rf/sub [:sign-in-enabled?]) - profile-picture (multiaccounts/displayed-photo account)] + [{:keys [on-enter-password button-label button-icon-left customization-color]}] + (let [{:keys [key-uid display-name] :as account} (rf/sub [:profile/multiaccount]) + {:keys [error processing password]} (rf/sub [:profile/login]) + sign-in-enabled? (rf/sub [:sign-in-enabled?]) + profile-picture (multiaccounts/displayed-photo account)] [:<> [rn/view {:style style/enter-password-container} [rn/view @@ -45,7 +43,7 @@ :type :primary :customization-color (or customization-color :primary) :accessibility-label :login-button - :icon-left :i/reveal + :icon-left button-icon-left :disabled? (or (not sign-in-enabled?) processing) :on-press (fn [] (rf/dispatch [:set-in [:profile/login :key-uid] key-uid]) diff --git a/src/status_im2/common/standard_authentication/standard_auth/view.cljs b/src/status_im2/common/standard_authentication/standard_auth/view.cljs index 07f17d258f..16d4373eea 100644 --- a/src/status_im2/common/standard_authentication/standard_auth/view.cljs +++ b/src/status_im2/common/standard_authentication/standard_auth/view.cljs @@ -17,7 +17,7 @@ (defn authorize [{:keys [on-enter-password biometric-auth? on-auth-success on-auth-fail on-close - fallback-button-label theme blur?]}] + auth-button-label theme blur? customization-color auth-button-icon-left]}] (biometric/get-supported-type (fn [biometric-type] (if (and biometric-auth? biometric-type) @@ -43,8 +43,10 @@ :shell? blur? :content (fn [] [enter-password/view - {:on-enter-password on-enter-password - :button-label fallback-button-label}])}])))))) + {:customization-color customization-color + :on-enter-password on-enter-password + :button-icon-left auth-button-icon-left + :button-label auth-button-label}])}])))))) (defn- view-internal [_] @@ -53,26 +55,31 @@ (fn [{:keys [biometric-auth? track-text customization-color - fallback-button-label + auth-button-label on-enter-password on-auth-success on-auth-fail + auth-button-icon-left size theme - blur?]}] + blur? + container-style]}] [rn/view {:style {:flex 1}} [quo/slide-button {:size size + :container-style container-style :customization-color customization-color :on-reset (when @reset-slider? #(reset! reset-slider? false)) :on-complete #(authorize {:on-close on-close + :auth-button-icon-left auth-button-icon-left :theme theme :blur? blur? + :customization-color customization-color :on-enter-password on-enter-password :biometric-auth? biometric-auth? :on-auth-success on-auth-success :on-auth-fail on-auth-fail - :fallback-button-label fallback-button-label}) + :auth-button-label auth-button-label}) :track-icon (if biometric-auth? :i/face-id :password) :track-text track-text}]]))) diff --git a/src/status_im2/contexts/profile/login/events.cljs b/src/status_im2/contexts/profile/login/events.cljs index 97020027a4..7a7c7c59c7 100644 --- a/src/status_im2/contexts/profile/login/events.cljs +++ b/src/status_im2/contexts/profile/login/events.cljs @@ -188,14 +188,16 @@ native-module/sha3)] {:json-rpc/call [{:method "accounts_verifyPassword" :params [hashed-password] - :on-success #(do (rf/dispatch [:profile.login/verified-database-password %]) (cb)) + :on-success #(rf/dispatch [:profile.login/verified-database-password % cb]) :on-error #(log/error "accounts_verifyPassword error" %)}]})) (rf/defn verify-database-password-success {:events [:profile.login/verified-database-password]} - [{:keys [db] :as cofx} valid?] + [{:keys [db] :as cofx} valid? callback] (if valid? (do + (when (fn? callback) + (callback)) {:db (update db :profile/login dissoc diff --git a/src/status_im2/contexts/syncing/setup_syncing/view.cljs b/src/status_im2/contexts/syncing/setup_syncing/view.cljs index 64853e4c5f..d8954743f8 100644 --- a/src/status_im2/contexts/syncing/setup_syncing/view.cljs +++ b/src/status_im2/contexts/syncing/setup_syncing/view.cljs @@ -126,7 +126,8 @@ :customization-color customization-color :on-enter-password on-enter-password :biometric-auth? false - :fallback-button-label (i18n/label :t/reveal-sync-code)}]])]] + :auth-button-label (i18n/label :t/reveal-sync-code) + :auth-button-icon-left :i/reveal}]])]] [rn/view {:style style/sync-code} [quo/divider-label {:tight? false} (i18n/label :t/have-a-sync-code?)] [quo/action-drawer diff --git a/src/status_im2/contexts/wallet/common/temp.cljs b/src/status_im2/contexts/wallet/common/temp.cljs index 097ac0b330..05e1825b7f 100644 --- a/src/status_im2/contexts/wallet/common/temp.cljs +++ b/src/status_im2/contexts/wallet/common/temp.cljs @@ -6,7 +6,6 @@ [react-native.core :as rn] [status-im2.common.resources :as status.resources] [status-im2.constants :as constants] - [status-im2.contexts.wallet.common.utils :as utils] [utils.i18n :as i18n] [utils.re-frame :as rf])) @@ -112,35 +111,6 @@ :account :default :customization-color :blue}) -(defn keypair-string - [full-name] - (let [first-name (utils/get-first-name full-name)] - (i18n/label :t/keypair-title {:name first-name}))) - -(defn create-account-state - [name] - [{:title (keypair-string name) - :image :avatar - :image-props {:full-name "A Y" - :size :xxs - :customization-color :blue} - :action :button - :action-props {:on-press #(js/alert "Button pressed!") - :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 "Button pressed!") - :button-text (i18n/label :t/edit) - :icon-left :i/placeholder - :alignment :flex-start} - :description :text - :description-props {:text (string/replace constants/path-default-wallet #"/" " / ")}}]) - (def network-names [:ethereum :optimism :arbitrum]) (def address "0x39cf6E0Ba4C4530735616e1Ee7ff5FbCB726fBd4") diff --git a/src/status_im2/contexts/wallet/common/utils.cljs b/src/status_im2/contexts/wallet/common/utils.cljs index 156ad8b1bf..5d5e20b2b2 100644 --- a/src/status_im2/contexts/wallet/common/utils.cljs +++ b/src/status_im2/contexts/wallet/common/utils.cljs @@ -1,7 +1,11 @@ (ns status-im2.contexts.wallet.common.utils - (:require - [clojure.string :as string])) + (:require [clojure.string :as string] + [status-im2.constants :as constants])) (defn get-first-name [full-name] (first (string/split full-name #" "))) + +(defn get-derivation-path + [number-of-accounts] + (str constants/path-wallet-root "/" number-of-accounts)) diff --git a/src/status_im2/contexts/wallet/create_account/view.cljs b/src/status_im2/contexts/wallet/create_account/view.cljs index ff2cd7d111..6e5a737129 100644 --- a/src/status_im2/contexts/wallet/create_account/view.cljs +++ b/src/status_im2/contexts/wallet/create_account/view.cljs @@ -5,20 +5,44 @@ [react-native.core :as rn] [react-native.safe-area :as safe-area] [reagent.core :as reagent] - [status-im2.contexts.wallet.common.temp :as temp] + [status-im2.common.standard-authentication.standard-auth.view :as standard-auth] + [status-im2.contexts.wallet.common.utils :as utils] [status-im2.contexts.wallet.create-account.style :as style] [utils.i18n :as i18n] [utils.re-frame :as rf])) (def diamond-emoji "\uD83D\uDC8E") +(defn keypair-string + [full-name] + (let [first-name (utils/get-first-name full-name)] + (i18n/label :t/keypair-title {:name first-name}))) + +(defn get-keypair-data + [name derivation-path] + [{:title (keypair-string name) + :button-props {:title (i18n/label :t/edit)} + :left-icon :i/placeholder + :description :text + :description-props {:text (i18n/label :t/on-device)}} + {:title (i18n/label :t/derivation-path) + :button-props {:title (i18n/label :t/edit)} + :left-icon :i/derivated-path + :description :text + :description-props {:text derivation-path}}]) + (defn- view-internal [] (let [top (safe-area/get-top) bottom (safe-area/get-bottom) account-color (reagent/atom :blue) emoji (reagent/atom diamond-emoji) + number-of-accounts (count (rf/sub [:profile/wallet-accounts])) + account-name (reagent/atom (i18n/label :t/default-account-name + {:number (inc number-of-accounts)})) + derivation-path (reagent/atom (utils/get-derivation-path number-of-accounts)) {:keys [public-key]} (rf/sub [:profile/profile]) + on-change-text #(reset! account-name %) display-name (first (rf/sub [:contacts/contact-two-names-by-identity public-key]))] (fn [{:keys [theme]}] [rn/view @@ -50,13 +74,14 @@ (reset! emoji selected-emoji))}]) :container-style style/reaction-button-container} :i/reaction]] [quo/title-input - {:color :red - :placeholder "Type something here" - :max-length 24 - :blur? true - :disabled? false - :default-value "Account 2" - :container-style style/title-input-container}] + {:customization-color @account-color + :placeholder "Type something here" + :on-change-text on-change-text + :max-length 24 + :blur? true + :disabled? false + :default-value @account-name + :container-style style/title-input-container}] [quo/divider-line] [rn/view {:style style/color-picker-container} @@ -74,13 +99,20 @@ [quo/category {:list-type :settings :label (i18n/label :t/origin) - :data (temp/create-account-state display-name)}] - [quo/slide-button - {:track-text (i18n/label :t/slide-to-sign) - :track-icon :face-id + :data (get-keypair-data display-name @derivation-path)}] + [standard-auth/view + {:size :size-48 + :track-text (i18n/label :t/slide-to-create-account) :customization-color @account-color - :on-complete (fn [] - (js/alert "Functionality not implemented")) + :on-enter-password (fn [entered-password] + (rf/dispatch [:wallet/derive-address-and-add-account + entered-password + {:emoji @emoji + :color @account-color + :path @derivation-path + :account-name @account-name}])) + :biometric-auth? false + :auth-button-label (i18n/label :t/confirm) :container-style (style/slide-button-container bottom)}]]))) (def view (quo.theme/with-theme view-internal)) diff --git a/src/status_im2/contexts/wallet/events.cljs b/src/status_im2/contexts/wallet/events.cljs index 8617e48ca2..d2ea57c7bf 100644 --- a/src/status_im2/contexts/wallet/events.cljs +++ b/src/status_im2/contexts/wallet/events.cljs @@ -1,5 +1,9 @@ (ns status-im2.contexts.wallet.events - (:require [utils.re-frame :as rf])) + (:require + [native-module.core :as native-module] + [taoensso.timbre :as log] + [utils.re-frame :as rf] + [utils.security.core :as security])) (rf/defn scan-address-success {:events [:wallet/scan-address-success]} @@ -10,3 +14,40 @@ {:events [:wallet/clean-scanned-address]} [{:keys [db]}] {:db (dissoc db :wallet/scanned-address)}) + +(rf/reg-event-fx :wallet/create-derived-addresses + (fn [{:keys [db]} [password {:keys [path]} on-success]] + (let [{:keys [wallet-root-address]} (:profile/profile db) + sha3-pwd (native-module/sha3 (str (security/safe-unmask-data password)))] + {:fx [[:json-rpc/call + [{:method "wallet_getDerivedAddresses" + :params [sha3-pwd wallet-root-address [path]] + :on-success on-success + :on-error #(log/info "failed to derive address " %)}]]]}))) + +(rf/reg-event-fx :wallet/add-account + (fn [{:keys [db]} [password {:keys [emoji account-name color]} {:keys [public-key address path]}]] + (let [key-uid (get-in db [:profile/profile :key-uid]) + sha3-pwd (native-module/sha3 (security/safe-unmask-data password)) + account-config {:key-uid key-uid + :wallet false + :chat false + :type :generated + :name account-name + :emoji emoji + :path path + :address address + :public-key public-key + :colorID color}] + {:fx [[:json-rpc/call + [{:method "accounts_addAccount" + :params [sha3-pwd account-config] + :on-success #(rf/dispatch [:navigate-to :wallet-accounts]) + :on-error #(log/info "failed to create account " %)}]]]}))) + +(rf/reg-event-fx :wallet/derive-address-and-add-account + (fn [_ [password account-details]] + (let [on-success (fn [derived-adress-details] + (rf/dispatch [:wallet/add-account password account-details + (first derived-adress-details)]))] + {:fx [[:dispatch [:wallet/create-derived-addresses password account-details on-success]]]}))) diff --git a/src/status_im2/subs/root.cljs b/src/status_im2/subs/root.cljs index 96a8629e84..83e30994c8 100644 --- a/src/status_im2/subs/root.cljs +++ b/src/status_im2/subs/root.cljs @@ -146,3 +146,4 @@ ;;wallet (reg-root-key-sub :wallet/scanned-address :wallet/scanned-address) +(reg-root-key-sub :wallet/create-account :wallet/create-account) diff --git a/src/utils/re_frame.cljs b/src/utils/re_frame.cljs index 14cc4257ea..aeba147c83 100644 --- a/src/utils/re_frame.cljs +++ b/src/utils/re_frame.cljs @@ -83,3 +83,5 @@ (def reg-fx re-frame/reg-fx) (def dispatch-sync re-frame/dispatch-sync) + +(def reg-event-fx re-frame/reg-event-fx) diff --git a/translations/en.json b/translations/en.json index 5ca6a4442b..bce5f62cd7 100644 --- a/translations/en.json +++ b/translations/en.json @@ -433,6 +433,7 @@ "decline": "Decline", "decryption-failed-content": "An error occured decrypting your data. You might need to erase your old data and generate a new account. Tap “Apply” to erase or “Cancel” to try again", "default": "Default", + "default-account-name": "Account {{number}}", "delete": "Delete", "delete-and-leave-group": "Delete and leave group", "delete-bootnode": "Delete bootnode", @@ -1893,6 +1894,7 @@ "select-token-to-swap": "Select token to Swap", "select-token-to-receive": "Select token to receive", "slide-to-reveal-code": "Slide to reveal code", + "slide-to-create-account": "Slide to create account", "minimum-received": "Minimum received", "powered-by-paraswap": "Powered by Paraswap", "priority": "Priority", @@ -2360,5 +2362,6 @@ "network-preferences": "Network preferences", "network-preferences-desc": "Select which network this address is happy to receive funds on", "layer-2": "Layer 2", - "manage-tokens": "Manage tokens" + "manage-tokens": "Manage tokens", + "sign transactions": "sign transactions" }