feat (wallet): add ability to create new account (#17496)

This commit is contained in:
Jamie Caprani 2023-10-26 10:45:33 +02:00 committed by GitHub
parent ab2ad0ec12
commit 56492949f1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 128 additions and 67 deletions

View File

@ -765,7 +765,7 @@ SPEC CHECKSUMS:
RNLanguages: 962e562af0d34ab1958d89bcfdb64fafc37c513e RNLanguages: 962e562af0d34ab1958d89bcfdb64fafc37c513e
RNPermissions: ad71dd4f767ec254f2cd57592fbee02afee75467 RNPermissions: ad71dd4f767ec254f2cd57592fbee02afee75467
RNReactNativeHapticFeedback: 2566b468cc8d0e7bb2f84b23adc0f4614594d071 RNReactNativeHapticFeedback: 2566b468cc8d0e7bb2f84b23adc0f4614594d071
RNReanimated: b2dc21e263319892469d656dc58fc26fb03eadab RNReanimated: 62e43ee6baafb9ba3d3af1857d7fd23a1d41bff0
RNShare: d82e10f6b7677f4b0048c23709bd04098d5aee6c RNShare: d82e10f6b7677f4b0048c23709bd04098d5aee6c
RNStaticSafeAreaInsets: 055ddbf5e476321720457cdaeec0ff2ba40ec1b8 RNStaticSafeAreaInsets: 055ddbf5e476321720457cdaeec0ff2ba40ec1b8
RNSVG: 80584470ff1ffc7994923ea135a3e5ad825546b9 RNSVG: 80584470ff1ffc7994923ea135a3e5ad825546b9
@ -777,6 +777,6 @@ SPEC CHECKSUMS:
TouchID: ba4c656d849cceabc2e4eef722dea5e55959ecf4 TouchID: ba4c656d849cceabc2e4eef722dea5e55959ecf4
Yoga: d24d6184b6b85f742536bd93bd07d69d7b9bb4c1 Yoga: d24d6184b6b85f742536bd93bd07d69d7b9bb4c1
PODFILE CHECKSUM: 6a5f0e6776ce4ef6193032d077947117ace77a87 PODFILE CHECKSUM: 84b749023e1c988c133d7a6ec09d125536e4a4fd
COCOAPODS: 1.12.0 COCOAPODS: 1.12.0

View File

@ -9,13 +9,11 @@
[utils.re-frame :as rf])) [utils.re-frame :as rf]))
(defn view (defn view
[{:keys [on-enter-password button-label]}] [{:keys [on-enter-password button-label button-icon-left customization-color]}]
(let [{:keys [key-uid display-name (let [{:keys [key-uid display-name] :as account} (rf/sub [:profile/multiaccount])
customization-color] {:keys [error processing password]} (rf/sub [:profile/login])
:as account} (rf/sub [:profile/multiaccount]) sign-in-enabled? (rf/sub [:sign-in-enabled?])
{:keys [error processing password]} (rf/sub [:profile/login]) profile-picture (multiaccounts/displayed-photo account)]
sign-in-enabled? (rf/sub [:sign-in-enabled?])
profile-picture (multiaccounts/displayed-photo account)]
[:<> [:<>
[rn/view {:style style/enter-password-container} [rn/view {:style style/enter-password-container}
[rn/view [rn/view
@ -45,7 +43,7 @@
:type :primary :type :primary
:customization-color (or customization-color :primary) :customization-color (or customization-color :primary)
:accessibility-label :login-button :accessibility-label :login-button
:icon-left :i/reveal :icon-left button-icon-left
:disabled? (or (not sign-in-enabled?) processing) :disabled? (or (not sign-in-enabled?) processing)
:on-press (fn [] :on-press (fn []
(rf/dispatch [:set-in [:profile/login :key-uid] key-uid]) (rf/dispatch [:set-in [:profile/login :key-uid] key-uid])

View File

@ -17,7 +17,7 @@
(defn authorize (defn authorize
[{:keys [on-enter-password biometric-auth? on-auth-success on-auth-fail on-close [{: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 (biometric/get-supported-type
(fn [biometric-type] (fn [biometric-type]
(if (and biometric-auth? biometric-type) (if (and biometric-auth? biometric-type)
@ -43,8 +43,10 @@
:shell? blur? :shell? blur?
:content (fn [] :content (fn []
[enter-password/view [enter-password/view
{:on-enter-password on-enter-password {:customization-color customization-color
:button-label fallback-button-label}])}])))))) :on-enter-password on-enter-password
:button-icon-left auth-button-icon-left
:button-label auth-button-label}])}]))))))
(defn- view-internal (defn- view-internal
[_] [_]
@ -53,26 +55,31 @@
(fn [{:keys [biometric-auth? (fn [{:keys [biometric-auth?
track-text track-text
customization-color customization-color
fallback-button-label auth-button-label
on-enter-password on-enter-password
on-auth-success on-auth-success
on-auth-fail on-auth-fail
auth-button-icon-left
size size
theme theme
blur?]}] blur?
container-style]}]
[rn/view {:style {:flex 1}} [rn/view {:style {:flex 1}}
[quo/slide-button [quo/slide-button
{:size size {:size size
:container-style container-style
:customization-color customization-color :customization-color customization-color
:on-reset (when @reset-slider? #(reset! reset-slider? false)) :on-reset (when @reset-slider? #(reset! reset-slider? false))
:on-complete #(authorize {:on-close on-close :on-complete #(authorize {:on-close on-close
:auth-button-icon-left auth-button-icon-left
:theme theme :theme theme
:blur? blur? :blur? blur?
:customization-color customization-color
:on-enter-password on-enter-password :on-enter-password on-enter-password
:biometric-auth? biometric-auth? :biometric-auth? biometric-auth?
:on-auth-success on-auth-success :on-auth-success on-auth-success
:on-auth-fail on-auth-fail :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-icon (if biometric-auth? :i/face-id :password)
:track-text track-text}]]))) :track-text track-text}]])))

View File

@ -188,14 +188,16 @@
native-module/sha3)] native-module/sha3)]
{:json-rpc/call [{:method "accounts_verifyPassword" {:json-rpc/call [{:method "accounts_verifyPassword"
:params [hashed-password] :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" %)}]})) :on-error #(log/error "accounts_verifyPassword error" %)}]}))
(rf/defn verify-database-password-success (rf/defn verify-database-password-success
{:events [:profile.login/verified-database-password]} {:events [:profile.login/verified-database-password]}
[{:keys [db] :as cofx} valid?] [{:keys [db] :as cofx} valid? callback]
(if valid? (if valid?
(do (do
(when (fn? callback)
(callback))
{:db (update db {:db (update db
:profile/login :profile/login
dissoc dissoc

View File

@ -126,7 +126,8 @@
:customization-color customization-color :customization-color customization-color
:on-enter-password on-enter-password :on-enter-password on-enter-password
:biometric-auth? false :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} [rn/view {:style style/sync-code}
[quo/divider-label {:tight? false} (i18n/label :t/have-a-sync-code?)] [quo/divider-label {:tight? false} (i18n/label :t/have-a-sync-code?)]
[quo/action-drawer [quo/action-drawer

View File

@ -6,7 +6,6 @@
[react-native.core :as rn] [react-native.core :as rn]
[status-im2.common.resources :as status.resources] [status-im2.common.resources :as status.resources]
[status-im2.constants :as constants] [status-im2.constants :as constants]
[status-im2.contexts.wallet.common.utils :as utils]
[utils.i18n :as i18n] [utils.i18n :as i18n]
[utils.re-frame :as rf])) [utils.re-frame :as rf]))
@ -112,35 +111,6 @@
:account :default :account :default
:customization-color :blue}) :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 network-names [:ethereum :optimism :arbitrum])
(def address "0x39cf6E0Ba4C4530735616e1Ee7ff5FbCB726fBd4") (def address "0x39cf6E0Ba4C4530735616e1Ee7ff5FbCB726fBd4")

View File

@ -1,7 +1,11 @@
(ns status-im2.contexts.wallet.common.utils (ns status-im2.contexts.wallet.common.utils
(:require (:require [clojure.string :as string]
[clojure.string :as string])) [status-im2.constants :as constants]))
(defn get-first-name (defn get-first-name
[full-name] [full-name]
(first (string/split full-name #" "))) (first (string/split full-name #" ")))
(defn get-derivation-path
[number-of-accounts]
(str constants/path-wallet-root "/" number-of-accounts))

View File

@ -5,20 +5,44 @@
[react-native.core :as rn] [react-native.core :as rn]
[react-native.safe-area :as safe-area] [react-native.safe-area :as safe-area]
[reagent.core :as reagent] [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] [status-im2.contexts.wallet.create-account.style :as style]
[utils.i18n :as i18n] [utils.i18n :as i18n]
[utils.re-frame :as rf])) [utils.re-frame :as rf]))
(def diamond-emoji "\uD83D\uDC8E") (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 (defn- view-internal
[] []
(let [top (safe-area/get-top) (let [top (safe-area/get-top)
bottom (safe-area/get-bottom) bottom (safe-area/get-bottom)
account-color (reagent/atom :blue) account-color (reagent/atom :blue)
emoji (reagent/atom diamond-emoji) 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]) {: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]))] display-name (first (rf/sub [:contacts/contact-two-names-by-identity public-key]))]
(fn [{:keys [theme]}] (fn [{:keys [theme]}]
[rn/view [rn/view
@ -50,13 +74,14 @@
(reset! emoji selected-emoji))}]) (reset! emoji selected-emoji))}])
:container-style style/reaction-button-container} :i/reaction]] :container-style style/reaction-button-container} :i/reaction]]
[quo/title-input [quo/title-input
{:color :red {:customization-color @account-color
:placeholder "Type something here" :placeholder "Type something here"
:max-length 24 :on-change-text on-change-text
:blur? true :max-length 24
:disabled? false :blur? true
:default-value "Account 2" :disabled? false
:container-style style/title-input-container}] :default-value @account-name
:container-style style/title-input-container}]
[quo/divider-line] [quo/divider-line]
[rn/view [rn/view
{:style style/color-picker-container} {:style style/color-picker-container}
@ -74,13 +99,20 @@
[quo/category [quo/category
{:list-type :settings {:list-type :settings
:label (i18n/label :t/origin) :label (i18n/label :t/origin)
:data (temp/create-account-state display-name)}] :data (get-keypair-data display-name @derivation-path)}]
[quo/slide-button [standard-auth/view
{:track-text (i18n/label :t/slide-to-sign) {:size :size-48
:track-icon :face-id :track-text (i18n/label :t/slide-to-create-account)
:customization-color @account-color :customization-color @account-color
:on-complete (fn [] :on-enter-password (fn [entered-password]
(js/alert "Functionality not implemented")) (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)}]]))) :container-style (style/slide-button-container bottom)}]])))
(def view (quo.theme/with-theme view-internal)) (def view (quo.theme/with-theme view-internal))

View File

@ -1,5 +1,9 @@
(ns status-im2.contexts.wallet.events (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 (rf/defn scan-address-success
{:events [:wallet/scan-address-success]} {:events [:wallet/scan-address-success]}
@ -10,3 +14,40 @@
{:events [:wallet/clean-scanned-address]} {:events [:wallet/clean-scanned-address]}
[{:keys [db]}] [{:keys [db]}]
{:db (dissoc db :wallet/scanned-address)}) {: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]]]})))

View File

@ -146,3 +146,4 @@
;;wallet ;;wallet
(reg-root-key-sub :wallet/scanned-address :wallet/scanned-address) (reg-root-key-sub :wallet/scanned-address :wallet/scanned-address)
(reg-root-key-sub :wallet/create-account :wallet/create-account)

View File

@ -83,3 +83,5 @@
(def reg-fx re-frame/reg-fx) (def reg-fx re-frame/reg-fx)
(def dispatch-sync re-frame/dispatch-sync) (def dispatch-sync re-frame/dispatch-sync)
(def reg-event-fx re-frame/reg-event-fx)

View File

@ -433,6 +433,7 @@
"decline": "Decline", "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", "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": "Default",
"default-account-name": "Account {{number}}",
"delete": "Delete", "delete": "Delete",
"delete-and-leave-group": "Delete and leave group", "delete-and-leave-group": "Delete and leave group",
"delete-bootnode": "Delete bootnode", "delete-bootnode": "Delete bootnode",
@ -1893,6 +1894,7 @@
"select-token-to-swap": "Select token to Swap", "select-token-to-swap": "Select token to Swap",
"select-token-to-receive": "Select token to receive", "select-token-to-receive": "Select token to receive",
"slide-to-reveal-code": "Slide to reveal code", "slide-to-reveal-code": "Slide to reveal code",
"slide-to-create-account": "Slide to create account",
"minimum-received": "Minimum received", "minimum-received": "Minimum received",
"powered-by-paraswap": "Powered by Paraswap", "powered-by-paraswap": "Powered by Paraswap",
"priority": "Priority", "priority": "Priority",
@ -2360,5 +2362,6 @@
"network-preferences": "Network preferences", "network-preferences": "Network preferences",
"network-preferences-desc": "Select which network this address is happy to receive funds on", "network-preferences-desc": "Select which network this address is happy to receive funds on",
"layer-2": "Layer 2", "layer-2": "Layer 2",
"manage-tokens": "Manage tokens" "manage-tokens": "Manage tokens",
"sign transactions": "sign transactions"
} }