Wallet: create account using recovery phrase (#19702)
Wallet: create account using recovery phrase (#19702)
This commit is contained in:
parent
1e55827c4b
commit
8aa586fe6e
|
@ -1,4 +1,4 @@
|
|||
(ns status-im.contexts.onboarding.enter-seed-phrase.style
|
||||
(ns status-im.common.enter-seed-phrase.style
|
||||
(:require
|
||||
[react-native.safe-area :as safe-area]))
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
(ns status-im.contexts.onboarding.enter-seed-phrase.view
|
||||
(ns status-im.common.enter-seed-phrase.view
|
||||
(:require
|
||||
[clojure.string :as string]
|
||||
[legacy.status-im.ethereum.mnemonic :as mnemonic]
|
||||
|
@ -7,8 +7,8 @@
|
|||
[react-native.core :as rn]
|
||||
[react-native.safe-area :as safe-area]
|
||||
[reagent.core :as reagent]
|
||||
[status-im.common.enter-seed-phrase.style :as style]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.contexts.onboarding.enter-seed-phrase.style :as style]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]
|
||||
[utils.security.core :as security]))
|
||||
|
@ -86,7 +86,7 @@
|
|||
(take 7)))
|
||||
|
||||
(defn screen
|
||||
[]
|
||||
[recovering-keypair?]
|
||||
(reagent/with-let [keyboard-shown? (reagent/atom false)
|
||||
keyboard-show-listener (.addListener rn/keyboard
|
||||
"keyboardDidShow"
|
||||
|
@ -103,9 +103,14 @@
|
|||
(reset! seed-phrase new-phrase))
|
||||
on-submit (fn []
|
||||
(swap! seed-phrase clean-seed-phrase)
|
||||
(rf/dispatch [:onboarding/seed-phrase-entered
|
||||
(security/mask-data @seed-phrase)
|
||||
set-invalid-seed-phrase]))]
|
||||
(if recovering-keypair?
|
||||
(rf/dispatch [:wallet/seed-phrase-entered
|
||||
(security/mask-data
|
||||
@seed-phrase)
|
||||
set-invalid-seed-phrase])
|
||||
(rf/dispatch [:onboarding/seed-phrase-entered
|
||||
(security/mask-data @seed-phrase)
|
||||
set-invalid-seed-phrase])))]
|
||||
(let [words-coll (mnemonic/passphrase->words @seed-phrase)
|
||||
last-word (peek words-coll)
|
||||
pick-suggested-word (fn [pressed-word]
|
||||
|
@ -147,7 +152,7 @@
|
|||
[rn/view {:style style/keyboard-container}
|
||||
[quo/predictive-keyboard
|
||||
{:type suggestions-state
|
||||
:blur? true
|
||||
:blur? (not recovering-keypair?)
|
||||
:text suggestions-text
|
||||
:words (keyboard-suggestions last-word)
|
||||
:on-press pick-suggested-word}]])])
|
||||
|
@ -155,14 +160,16 @@
|
|||
(.remove keyboard-show-listener)
|
||||
(.remove keyboard-hide-listener))))
|
||||
|
||||
(defn enter-seed-phrase
|
||||
(defn view
|
||||
[]
|
||||
(let [{navigation-bar-top :top} (safe-area/get-insets)]
|
||||
[rn/view {:style style/full-layout}
|
||||
[rn/keyboard-avoiding-view {:style style/page-container}
|
||||
[quo/page-nav
|
||||
{:margin-top navigation-bar-top
|
||||
:background :blur
|
||||
:icon-name :i/arrow-left
|
||||
:on-press #(rf/dispatch [:navigate-back])}]
|
||||
[screen]]]))
|
||||
(fn []
|
||||
(let [{:keys [recovering-keypair?]} (rf/sub [:get-screen-params])]
|
||||
[rn/view {:style style/full-layout}
|
||||
[rn/keyboard-avoiding-view {:style style/page-container}
|
||||
[quo/page-nav
|
||||
{:margin-top navigation-bar-top
|
||||
:background :blur
|
||||
:icon-name (if recovering-keypair? :i/close :i/arrow-left)
|
||||
:on-press #(rf/dispatch [:navigate-back])}]
|
||||
[screen recovering-keypair?]]]))))
|
|
@ -2,6 +2,7 @@
|
|||
(:require [camel-snake-kebab.extras :as cske]
|
||||
[status-im.contexts.wallet.data-store :as data-store]
|
||||
[utils.re-frame :as rf]
|
||||
[utils.security.core :as security]
|
||||
[utils.transforms :as transforms]))
|
||||
|
||||
(defn get-keypairs-success
|
||||
|
@ -21,14 +22,32 @@
|
|||
|
||||
(rf/reg-event-fx :wallet/confirm-account-origin confirm-account-origin)
|
||||
|
||||
(defn store-secret-phrase
|
||||
[{:keys [db]} [{:keys [secret-phrase random-phrase]}]]
|
||||
(defn store-seed-phrase
|
||||
[{:keys [db]} [{:keys [seed-phrase random-phrase]}]]
|
||||
{:db (-> db
|
||||
(assoc-in [:wallet :ui :create-account :secret-phrase] secret-phrase)
|
||||
(assoc-in [:wallet :ui :create-account :seed-phrase] seed-phrase)
|
||||
(assoc-in [:wallet :ui :create-account :random-phrase] random-phrase))
|
||||
:fx [[:dispatch-later [{:ms 20 :dispatch [:navigate-to :screen/wallet.check-your-backup]}]]]})
|
||||
|
||||
(rf/reg-event-fx :wallet/store-secret-phrase store-secret-phrase)
|
||||
(rf/reg-event-fx :wallet/store-seed-phrase store-seed-phrase)
|
||||
|
||||
(defn seed-phrase-validated
|
||||
[{:keys [db]} [seed-phrase]]
|
||||
{:db (assoc-in db [:wallet :ui :create-account :seed-phrase] seed-phrase)
|
||||
:fx [[:dispatch [:navigate-to :screen/wallet.keypair-name]]]})
|
||||
|
||||
(rf/reg-event-fx :wallet/seed-phrase-validated seed-phrase-validated)
|
||||
|
||||
(defn seed-phrase-entered
|
||||
[_ [seed-phrase on-error]]
|
||||
{:fx [[:multiaccount/validate-mnemonic
|
||||
[seed-phrase
|
||||
(fn [mnemonic key-uid]
|
||||
(rf/dispatch [:wallet/seed-phrase-validated
|
||||
mnemonic key-uid]))
|
||||
on-error]]]})
|
||||
|
||||
(rf/reg-event-fx :wallet/seed-phrase-entered seed-phrase-entered)
|
||||
|
||||
(defn new-keypair-created
|
||||
[{:keys [db]} [{:keys [new-keypair]}]]
|
||||
|
@ -39,10 +58,10 @@
|
|||
|
||||
(defn new-keypair-continue
|
||||
[{:keys [db]} [{:keys [keypair-name]}]]
|
||||
(let [secret-phrase (get-in db [:wallet :ui :create-account :secret-phrase])]
|
||||
(let [seed-phrase (get-in db [:wallet :ui :create-account :seed-phrase])]
|
||||
{:fx [[:effects.wallet/create-account-from-mnemonic
|
||||
{:secret-phrase secret-phrase
|
||||
:keypair-name keypair-name}]]}))
|
||||
{:seed-phrase (security/safe-unmask-data seed-phrase)
|
||||
:keypair-name keypair-name}]]}))
|
||||
|
||||
(rf/reg-event-fx :wallet/new-keypair-continue new-keypair-continue)
|
||||
|
||||
|
|
|
@ -12,12 +12,12 @@
|
|||
result-db (:db effects)]
|
||||
(is (match? result-db expected-db))))
|
||||
|
||||
(deftest store-secret-phrase
|
||||
(deftest store-seed-phrase
|
||||
(let [db {}
|
||||
props [{:secret-phrase "test-secret" :random-phrase "random-test"}]
|
||||
expected-db {:wallet {:ui {:create-account {:secret-phrase "test-secret"
|
||||
props [{:seed-phrase "test-secret" :random-phrase "random-test"}]
|
||||
expected-db {:wallet {:ui {:create-account {:seed-phrase "test-secret"
|
||||
:random-phrase "random-test"}}}}
|
||||
effects (events/store-secret-phrase {:db db} props)
|
||||
effects (events/store-seed-phrase {:db db} props)
|
||||
result-db (:db effects)]
|
||||
(is (match? result-db expected-db))))
|
||||
|
||||
|
@ -30,10 +30,10 @@
|
|||
(is (match? result-db expected-db))))
|
||||
|
||||
(deftest new-keypair-continue
|
||||
(let [db {:wallet {:ui {:create-account {:secret-phrase "test-secret"}}}}
|
||||
(let [db {:wallet {:ui {:create-account {:seed-phrase "test-secret"}}}}
|
||||
props [{:keypair-name "test-keypair"}]
|
||||
expected-effects [[:effects.wallet/create-account-from-mnemonic
|
||||
{:secret-phrase "test-secret" :keypair-name "test-keypair"}]]
|
||||
{:seed-phrase "test-secret" :keypair-name "test-keypair"}]]
|
||||
effects (events/new-keypair-continue {:db db} props)]
|
||||
(is (match? effects {:fx expected-effects}))))
|
||||
|
||||
|
|
|
@ -10,7 +10,8 @@
|
|||
[status-im.contexts.wallet.add-account.create-account.new-keypair.backup-recovery-phrase.style :as
|
||||
style]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
[utils.re-frame :as rf]
|
||||
[utils.security.core :as security]))
|
||||
|
||||
(defn- word-item
|
||||
[item index _ increment]
|
||||
|
@ -54,14 +55,14 @@
|
|||
:3 false})
|
||||
revealed? (reagent/atom false)
|
||||
customization-color (rf/sub [:profile/customization-color])
|
||||
secret-phrase (reagent/atom [])
|
||||
seed-phrase (reagent/atom [])
|
||||
random-phrase (reagent/atom [])]
|
||||
(fn []
|
||||
(let [theme (quo.theme/use-theme)]
|
||||
|
||||
(rn/use-mount
|
||||
(fn []
|
||||
(native-module/get-random-mnemonic #(reset! secret-phrase (string/split % #"\s")))
|
||||
(native-module/get-random-mnemonic #(reset! seed-phrase (string/split % #"\s")))
|
||||
(native-module/get-random-mnemonic #(reset! random-phrase (string/split % #"\s")))))
|
||||
[rn/view {:style {:flex 1}}
|
||||
[quo/page-nav
|
||||
|
@ -74,14 +75,14 @@
|
|||
:description-text (i18n/label :t/backup-recovery-phrase-description)
|
||||
:container-style {:padding-bottom 8}}]
|
||||
[rn/view {:style (style/seed-phrase-container theme)}
|
||||
(when (pos? (count @secret-phrase))
|
||||
(when (pos? (count @seed-phrase))
|
||||
[:<>
|
||||
[words-column
|
||||
{:words @secret-phrase
|
||||
{:words @seed-phrase
|
||||
:first-half? true}]
|
||||
[rn/view {:style (style/separator theme)}]
|
||||
[words-column
|
||||
{:words @secret-phrase
|
||||
{:words @seed-phrase
|
||||
:first-half? false}]])
|
||||
(when-not @revealed?
|
||||
[rn/view {:style style/blur-container}
|
||||
|
@ -107,8 +108,9 @@
|
|||
:button-one-label (i18n/label :t/i-have-written)
|
||||
:button-one-props {:disabled? (some false? (vals @checked?))
|
||||
:customization-color customization-color
|
||||
:on-press #(rf/dispatch [:wallet/store-secret-phrase
|
||||
{:secret-phrase @secret-phrase
|
||||
:on-press #(rf/dispatch [:wallet/store-seed-phrase
|
||||
{:seed-phrase (security/mask-data
|
||||
@seed-phrase)
|
||||
:random-phrase @random-phrase}])}}]
|
||||
[quo/text
|
||||
{:size :paragraph-2
|
||||
|
|
|
@ -5,7 +5,8 @@
|
|||
[reagent.core :as reagent]
|
||||
[status-im.contexts.wallet.add-account.create-account.new-keypair.check-your-backup.style :as style]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
[utils.re-frame :as rf]
|
||||
[utils.security.core :as security]))
|
||||
|
||||
(def secret-words-count 12)
|
||||
|
||||
|
@ -60,15 +61,16 @@
|
|||
|
||||
(defn view
|
||||
[]
|
||||
(let [random-indices (random-selection)
|
||||
quiz-index (reagent/atom 0)
|
||||
incorrect-count (reagent/atom 0)
|
||||
show-error? (reagent/atom false)
|
||||
{:keys [secret-phrase random-phrase]} (rf/sub [:wallet/create-account])]
|
||||
(let [random-indices (random-selection)
|
||||
quiz-index (reagent/atom 0)
|
||||
incorrect-count (reagent/atom 0)
|
||||
show-error? (reagent/atom false)
|
||||
{:keys [seed-phrase random-phrase]} (rf/sub [:wallet/create-account])
|
||||
unmasked-seed-phrase (security/safe-unmask-data seed-phrase)]
|
||||
(fn []
|
||||
(let [current-word-index (get random-indices
|
||||
(min @quiz-index (dec questions-count)))
|
||||
current-word (get secret-phrase current-word-index)
|
||||
current-word (get unmasked-seed-phrase current-word-index)
|
||||
[options-row-0 options-row-1] (random-words-with-string random-phrase current-word)
|
||||
on-button-press (fn [word]
|
||||
(if (= word current-word)
|
||||
|
@ -113,7 +115,7 @@
|
|||
|
||||
:else
|
||||
:disabled)
|
||||
:word (get secret-phrase num)
|
||||
:word (get unmasked-seed-phrase num)
|
||||
:number (inc num)
|
||||
:on-press #(when (= @quiz-index index)
|
||||
(reset! show-error? false))}])
|
||||
|
|
|
@ -47,8 +47,8 @@
|
|||
{:actions :one-action
|
||||
:button-one-label (i18n/label :t/continue)
|
||||
:button-one-props {:disabled? (or (pos? error)
|
||||
(<= (count keypair-name)
|
||||
keypair-name-min-length))
|
||||
(< (count keypair-name)
|
||||
keypair-name-min-length))
|
||||
:customization-color customization-color
|
||||
:on-press on-continue}
|
||||
:container-style style/bottom-action}]}
|
||||
|
|
|
@ -20,7 +20,9 @@
|
|||
{:icon :i/seed
|
||||
:accessibility-label :import-using-phrase
|
||||
:label (i18n/label :t/import-using-phrase)
|
||||
:add-divider? true}
|
||||
:add-divider? true
|
||||
:on-press #(rf/dispatch [:navigate-to :screen/wallet.enter-seed-phrase
|
||||
{:recovering-keypair? true}])}
|
||||
{:icon :i/key
|
||||
:accessibility-label :import-private-key
|
||||
:label (i18n/label :t/import-private-key)
|
||||
|
|
|
@ -6,9 +6,11 @@
|
|||
|
||||
(rf/reg-fx
|
||||
:effects.wallet/create-account-from-mnemonic
|
||||
(fn [{:keys [secret-phrase keypair-name]}]
|
||||
(fn [{:keys [seed-phrase keypair-name]}]
|
||||
(native-module/create-account-from-mnemonic
|
||||
{:MnemonicPhrase (string/join " " secret-phrase)}
|
||||
{:MnemonicPhrase (if (string? seed-phrase)
|
||||
seed-phrase
|
||||
(string/join " " seed-phrase))}
|
||||
(fn [new-keypair]
|
||||
(rf/dispatch [:wallet/new-keypair-created
|
||||
{:new-keypair (assoc new-keypair :keypair-name keypair-name)}])))))
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
[legacy.status-im.ui.screens.screens :as old-screens]
|
||||
[quo.foundations.colors :as colors]
|
||||
[status-im.common.emoji-picker.view :as emoji-picker]
|
||||
[status-im.common.enter-seed-phrase.view :as enter-seed-phrase]
|
||||
[status-im.common.lightbox.view :as lightbox]
|
||||
[status-im.config :as config]
|
||||
[status-im.contexts.chat.group-create.view :as group-create]
|
||||
|
@ -29,7 +30,6 @@
|
|||
[status-im.contexts.onboarding.create-profile.view :as create-profile]
|
||||
[status-im.contexts.onboarding.enable-biometrics.view :as enable-biometrics]
|
||||
[status-im.contexts.onboarding.enable-notifications.view :as enable-notifications]
|
||||
[status-im.contexts.onboarding.enter-seed-phrase.view :as enter-seed-phrase]
|
||||
[status-im.contexts.onboarding.generating-keys.view :as generating-keys]
|
||||
[status-im.contexts.onboarding.identifiers.view :as identifiers]
|
||||
[status-im.contexts.onboarding.intro.view :as intro]
|
||||
|
@ -304,7 +304,7 @@
|
|||
:layout options/onboarding-transparent-layout
|
||||
:animations transitions/push-animations-for-transparent-background
|
||||
:popGesture false}
|
||||
:component enter-seed-phrase/enter-seed-phrase}
|
||||
:component enter-seed-phrase/view}
|
||||
|
||||
{:name :screen/onboarding.enable-notifications
|
||||
:options {:theme :dark
|
||||
|
@ -429,6 +429,9 @@
|
|||
:options {:insets {:top? true :bottom? true}}
|
||||
:component wallet-keypair-name/view}
|
||||
|
||||
{:name :screen/wallet.enter-seed-phrase
|
||||
:component enter-seed-phrase/view}
|
||||
|
||||
{:name :screen/wallet.share-address
|
||||
:options options/transparent-screen-options
|
||||
:component wallet-share-address/view}
|
||||
|
|
|
@ -2546,8 +2546,8 @@
|
|||
"derivation-path-desc": "Derivation paths are the routes your Status Wallet uses to generate addresses from your private key.",
|
||||
"select-networks": "Select networks",
|
||||
"generating-keypair": "Generating keypair...",
|
||||
"keypair-name": "Keypair name",
|
||||
"keypair-name-description": "Name keypair for your own personal reference",
|
||||
"keypair-name": "Key pair name",
|
||||
"keypair-name-description": "Name key pair for your own personal reference",
|
||||
"keypair-name-input-placeholder": "Collectibles account, Old vault....",
|
||||
"goerli-testnet-toggle-confirmation": "Are you sure you want to toggle Goerli? This will log you out and you will have to login again.",
|
||||
"bridged-to": "Bridged to {{network}}",
|
||||
|
@ -2582,7 +2582,6 @@
|
|||
"one-user-was-invited": "1 user was invited",
|
||||
"n-users-were-invited": "{{count}} users were invited",
|
||||
"invite-friend-to-status": "Invite friends to Status",
|
||||
"send-community-link": "Send community link",
|
||||
"enter-private-key": "Enter the private key of an address",
|
||||
"enter-private-key-placeholder": "Enter your private key",
|
||||
"import-private-key-info": "New addresses cannot be derived from an account imported from a private key. Import using a seed phrase if you wish to derive addresses.",
|
||||
|
@ -2590,5 +2589,6 @@
|
|||
"private-key-public-address": "Public address of private key",
|
||||
"this-account-has-no-activity": "This account has no activity",
|
||||
"this-address-has-activity": "This address has activity",
|
||||
"scanning-for-activity": "Scanning for activity..."
|
||||
"scanning-for-activity": "Scanning for activity...",
|
||||
"send-community-link": "Send community link"
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue