[#19232] - Fix derivation path generation and keypair creation (#19531)

* Add more default dependencies to slide button

* Fix wallet account creation: derivation paths and keypairs
This commit is contained in:
Ulises Manuel 2024-05-24 10:03:02 -06:00 committed by GitHub
parent f65c10502b
commit 49a41f4787
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 446 additions and 233 deletions

View File

@ -24,7 +24,7 @@
:on-auth-success on-auth-success
:on-auth-fail on-auth-fail
:auth-button-label auth-button-label}]))
(into [] (concat [theme] dependencies)))]
(vec (conj dependencies on-auth-success on-auth-fail)))]
[quo/slide-button
{:container-style container-style
:size size

View File

@ -38,8 +38,7 @@
:disabled? (string/blank? @account-name)
:accessibility-label :confirm-button-label
:on-press #(rf/dispatch [:wallet/add-account
{:sha3-pwd nil
:type :watch
{:type :watch
:account-name @account-name
:emoji @account-emoji
:color @account-color}

View File

@ -1,6 +1,10 @@
(ns status-im.contexts.wallet.add-account.create-account.events
(:require [camel-snake-kebab.extras :as cske]
[clojure.string :as string]
[status-im.constants :as constants]
[status-im.contexts.wallet.add-account.create-account.utils :as create-account.utils]
[status-im.contexts.wallet.data-store :as data-store]
[taoensso.timbre :as log]
[utils.re-frame :as rf]
[utils.security.core :as security]
[utils.transforms :as transforms]))
@ -22,14 +26,18 @@
(rf/reg-event-fx :wallet/confirm-account-origin confirm-account-origin)
(defn store-seed-phrase
(defn store-new-seed-phrase
[{:keys [db]} [{:keys [seed-phrase random-phrase]}]]
{:db (-> db
(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.confirm-backup]}]]]})
{:db (update-in db
[:wallet :ui :create-account :new-keypair]
assoc
:seed-phrase seed-phrase
:random-phrase random-phrase)
:fx [[:dispatch-later
[{:ms 20
:dispatch [:navigate-to :screen/wallet.confirm-backup]}]]]})
(rf/reg-event-fx :wallet/store-seed-phrase store-seed-phrase)
(rf/reg-event-fx :wallet/store-new-seed-phrase store-new-seed-phrase)
(defn seed-phrase-validated
[{:keys [db]} [seed-phrase]]
@ -43,33 +51,45 @@
{:fx [[:multiaccount/validate-mnemonic
[seed-phrase
(fn [mnemonic key-uid]
(rf/dispatch [:wallet/seed-phrase-validated
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]}]]
{:db (assoc-in db [:wallet :ui :create-account :new-keypair] new-keypair)
:fx [[:dispatch [:navigate-back-to :screen/wallet.create-account]]]})
(defn store-account-generated
[{:keys [db]} [{:keys [new-account-data keypair-name]}]]
(let [new-account (update new-account-data :mnemonic security/mask-data)]
{:db (-> db
(update-in [:wallet :ui :create-account :new-keypair]
assoc
:new-account-data new-account
:keypair-name keypair-name)
(update-in [:wallet :ui :create-account :new-keypair]
dissoc
:seed-phrase
:random-phrase))
:fx [[:dispatch [:navigate-back-to :screen/wallet.create-account]]]}))
(rf/reg-event-fx :wallet/new-keypair-created new-keypair-created)
(rf/reg-event-fx :wallet/store-account-generated store-account-generated)
(defn new-keypair-continue
(defn generate-account-for-keypair
[{:keys [db]} [{:keys [keypair-name]}]]
(let [seed-phrase (get-in db [:wallet :ui :create-account :seed-phrase])]
(let [seed-phrase (-> db :wallet :ui :create-account :new-keypair :seed-phrase)]
{:fx [[:effects.wallet/create-account-from-mnemonic
{:seed-phrase (security/safe-unmask-data seed-phrase)
:keypair-name keypair-name}]]}))
{:mnemonic-phrase (security/safe-unmask-data seed-phrase)
:paths [constants/path-default-wallet]
:on-success (fn [new-account-data]
(rf/dispatch [:wallet/store-account-generated
{:new-account-data new-account-data
:keypair-name keypair-name}]))}]]}))
(rf/reg-event-fx :wallet/new-keypair-continue new-keypair-continue)
(rf/reg-event-fx :wallet/generate-account-for-keypair generate-account-for-keypair)
(defn clear-new-keypair
(defn clear-create-account-data
[{:keys [db]}]
{:db (update-in db [:wallet :ui :create-account] dissoc :new-keypair)})
(rf/reg-event-fx :wallet/clear-new-keypair clear-new-keypair)
(rf/reg-event-fx :wallet/clear-create-account clear-create-account-data)
(defn get-derived-addresses
[{:keys [db]} [{:keys [password derived-from paths]}]]
@ -80,6 +100,21 @@
(rf/reg-event-fx :wallet/get-derived-addresses get-derived-addresses)
(rf/reg-event-fx
:wallet/next-derivation-path
(fn [_ [{:keys [on-success keypair-uid]}]]
{:fx [[:json-rpc/call
[{:method "accounts_resolveSuggestedPathForKeypair"
:params [keypair-uid]
:on-success on-success
:on-error (fn [error]
(log/error
"Failed to resolve next path derivation path"
{:event :wallet/next-derivation-path
:method "accounts_resolveSuggestedPathForKeypair"
:error error
:params keypair-uid}))}]]]}))
(defn get-derived-addresses-success
[{:keys [db]} [response]]
(let [derived-address (first response)]
@ -105,3 +140,53 @@
:wallet/clear-private-key-data
(fn [{:keys [db]} _]
{:db (update-in db [:wallet :ui :create-account] dissoc :private-key :public-address)}))
(rf/reg-event-fx
:wallet/create-keypair-with-account
(fn [{db :db} [password account-preferences]]
(let [{:keys [keypair-name
new-account-data]} (-> db :wallet :ui :create-account :new-keypair)
keypair-with-account (create-account.utils/prepare-new-account
{:keypair-name keypair-name
:account-data new-account-data
:account-preferences account-preferences})
new-address (some-> new-account-data
(create-account.utils/first-derived-account)
(:address)
(string/lower-case))
unmasked-password (security/safe-unmask-data password)]
{:fx [[:json-rpc/call
[{:method "accounts_addKeypair"
:params [unmasked-password keypair-with-account]
:on-success [:wallet/add-account-success new-address]
:on-error #(log/error "Failed to add Keypair and create account" %)}]]]})))
(defn import-and-create-keypair-with-account
[{db :db} [{:keys [password account-preferences]}]]
(let [account-data (-> db :wallet :ui :create-account :new-keypair :new-account-data)
unmasked-mnemonic (security/safe-unmask-data (:mnemonic account-data))
unmasked-password (security/safe-unmask-data password)]
{:fx [[:json-rpc/call
[{:method "accounts_importMnemonic"
:params [unmasked-mnemonic unmasked-password]
:on-success #(rf/dispatch
[:wallet/create-keypair-with-account password account-preferences])}]]]}))
(rf/reg-event-fx :wallet/import-and-create-keypair-with-account import-and-create-keypair-with-account)
(rf/reg-event-fx
:wallet/derive-address-and-add-account
(fn [_ [{:keys [password derived-from-address derivation-path account-preferences]}]]
{:fx [[:json-rpc/call
[{:method "wallet_getDerivedAddresses"
:params [(security/safe-unmask-data password)
derived-from-address
[derivation-path]]
:on-success (fn [[derived-account]]
(rf/dispatch [:wallet/add-account
(assoc account-preferences :password password)
derived-account]))
:on-error #(log/info "Failed to get derived addresses"
derived-from-address
%)}]]]}))

View File

@ -1,8 +1,10 @@
(ns status-im.contexts.wallet.add-account.create-account.events-test
(:require
[cljs.test :refer-macros [deftest is]]
matcher-combinators.test
[status-im.contexts.wallet.add-account.create-account.events :as events]))
[matcher-combinators.test]
[status-im.constants :as constants]
[status-im.contexts.wallet.add-account.create-account.events :as events]
[utils.security.core :as security]))
(deftest confirm-account-origin
(let [db {:wallet {:ui {:create-account {}}}}
@ -15,32 +17,60 @@
(deftest store-seed-phrase
(let [db {}
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-seed-phrase {:db db} props)
expected-db {:wallet {:ui {:create-account {:new-keypair {:seed-phrase "test-secret"
:random-phrase "random-test"}}}}}
effects (events/store-new-seed-phrase {:db db} props)
result-db (:db effects)]
(is (match? result-db expected-db))))
(deftest new-keypair-created
(let [db {}
props [{:new-keypair "test-keypair"}]
expected-db {:wallet {:ui {:create-account {:new-keypair "test-keypair"}}}}
effects (events/new-keypair-created {:db db} props)
result-db (:db effects)]
(is (match? result-db expected-db))))
(deftest store-account-generated
(let [db {:wallet {:ui {:create-account
{:new-keypair {:seed-phrase "test-secret"
:random-phrase "random-test"}}}}}
mnemonic "my mnemonic"
masked-mnemonic (security/mask-data mnemonic)
props [{:new-account-data {"test" "data"
:mnemonic mnemonic}
:keypair-name "new-keypair-name"}]
expected-db {:wallet {:ui {:create-account
{:new-keypair
{:new-account-data {"test" "data"
:mnemonic masked-mnemonic}
:keypair-name "new-keypair-name"}}}}}
effects (events/store-account-generated {:db db} props)
result-db (:db effects)
remove-mnemonic #(update-in %
[:wallet :ui :create-account :new-keypair :new-account-data]
dissoc
:mnemonic)
unmask-mnemonic #(-> %
:wallet
:ui
:create-account
:new-keypair
:new-account-data
:mnemonic
security/safe-unmask-data)]
(is (= (remove-mnemonic result-db) (remove-mnemonic expected-db)))
(is (= (unmask-mnemonic result-db) (unmask-mnemonic expected-db)))))
(deftest new-keypair-continue
(let [db {:wallet {:ui {:create-account {:seed-phrase "test-secret"}}}}
(deftest generate-account-for-keypair
(let [db {:wallet {:ui {:create-account {:new-keypair {:seed-phrase "test-secret"}}}}}
props [{:keypair-name "test-keypair"}]
expected-effects [[:effects.wallet/create-account-from-mnemonic
{:seed-phrase "test-secret" :keypair-name "test-keypair"}]]
effects (events/new-keypair-continue {:db db} props)]
(is (match? effects {:fx expected-effects}))))
{:mnemonic-phrase "test-secret"
:paths [constants/path-default-wallet]}]]
effects (events/generate-account-for-keypair {:db db} props)]
(is (match?
(update-in effects [:fx 0 1] dissoc :on-success)
{:fx expected-effects}))
(is (some? (get-in effects [:fx 0 1 :on-success])))))
(deftest clear-new-keypair
(deftest clear-create-account-data
(let [db {:wallet {:ui {:create-account {:new-keypair "test-keypair"}}}}
expected-db {:wallet {:ui {:create-account {}}}}
effects (events/clear-new-keypair {:db db})]
effects (events/clear-create-account-data {:db db})]
(is (match? (:db effects) expected-db))))
(deftest get-derived-addresses-test

View File

@ -52,8 +52,8 @@
:import-private-key
(not-implemented/alert)
:new-key-pair
(rf/dispatch [:wallet/new-keypair-continue
:new-keypair
(rf/dispatch [:wallet/generate-account-for-keypair
{:keypair-name key-pair-name}])
(js/alert "Unknown workflow")))
[workflow key-pair-name])

View File

@ -108,7 +108,7 @@
: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-seed-phrase
:on-press #(rf/dispatch [:wallet/store-new-seed-phrase
{:seed-phrase (security/mask-data
@seed-phrase)
:random-phrase @random-phrase}])}}]

View File

@ -65,7 +65,7 @@
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])
{:keys [seed-phrase random-phrase]} (rf/sub [:wallet/create-account-new-keypair])
unmasked-seed-phrase (security/safe-unmask-data seed-phrase)]
(fn []
(let [current-word-index (get random-indices
@ -82,7 +82,7 @@
(when (= @quiz-index questions-count)
(rf/dispatch [:navigate-to
:screen/wallet.keypair-name
{:workflow :new-key-pair}])))
{:workflow :new-keypair}])))
(do
(when (> @incorrect-count 0)
(rf/dispatch [:show-bottom-sheet

View File

@ -1,19 +1,29 @@
(ns status-im.contexts.wallet.add-account.create-account.utils)
(ns status-im.contexts.wallet.add-account.create-account.utils
(:require [status-im.constants :as constants]))
(defn prepare-new-keypair
[{:keys [new-keypair address account-name account-color emoji derivation-path]}]
(assoc new-keypair
:name (:keypair-name new-keypair)
:key-uid (:keyUid new-keypair)
:type :seed
:derived-from address
:accounts [{:keypair-name (:keypair-name new-keypair)
:key-uid (:keyUid new-keypair)
:seed-phrase (:mnemonic new-keypair)
:public-key (:publicKey new-keypair)
:name account-name
:type :seed
:emoji emoji
:colorID account-color
:path derivation-path
:address (:address new-keypair)}]))
(defn first-derived-account
[account-data]
(-> account-data :derived first val))
(defn prepare-new-account
[{keypair-name :keypair-name
{:keys [keyUid address] :as account} :account-data
{:keys [account-name color emoji]} :account-preferences}]
(let [account-to-create (first-derived-account account)
account-config {:address (:address account-to-create)
:key-uid keyUid
:wallet false
:chat false
:type :seed
:path constants/path-default-wallet
:public-key (:publicKey account-to-create)
:name account-name
:emoji emoji
:colorID color
:hidden false}]
{:key-uid keyUid
:name keypair-name
:type :seed
:derived-from address
:last-used-derivation-index 0
:accounts [account-config]}))

View File

@ -12,14 +12,11 @@
[status-im.common.standard-authentication.core :as standard-auth]
[status-im.constants :as constants]
[status-im.contexts.wallet.add-account.create-account.style :as style]
[status-im.contexts.wallet.add-account.create-account.utils :as create-account.utils]
[status-im.contexts.wallet.common.utils :as 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]
[utils.security.core :as security]
[utils.string]))
(defn- get-keypair-data
@ -57,107 +54,47 @@
:description :text
:description-props {:text formatted-path}}]))
(defn view
(defn- avatar
[{:keys [account-color emoji on-select-emoji]}]
[rn/view {:style style/account-avatar-container}
[quo/account-avatar
{:customization-color account-color
:size 80
:emoji emoji
:type :default}]
[quo/button
{:size 32
:type :grey
:background :photo
:icon-only? true
:on-press #(rf/dispatch [:emoji-picker/open {:on-select on-select-emoji}])
:container-style style/reaction-button-container}
:i/reaction]])
(defn- input
[_]
(let [top (safe-area/get-top)
bottom (safe-area/get-bottom)
{window-width :width} (rn/get-window)
account-color (reagent/atom (rand-nth colors/account-colors))
emoji (reagent/atom (emoji-picker.utils/random-emoji))
account-name (reagent/atom "")
on-change-text #(reset! account-name %)
show-account-origin #(rf/dispatch [:show-bottom-sheet
{:content account-origin/view}])]
(fn []
(let [theme (quo.theme/use-theme)
number-of-accounts (count (rf/sub
[:wallet/accounts-without-watched-accounts]))
{:keys [address customization-color]} (rf/sub [:profile/profile])
{:keys [new-keypair]} (rf/sub [:wallet/create-account])
keypairs (rf/sub [:wallet/keypairs])
selected-keypair-uid (rf/sub [:wallet/selected-keypair-uid])
placeholder (i18n/label :t/default-account-placeholder)
derivation-path (utils/get-derivation-path
number-of-accounts)
keypair (some #(when (= (:key-uid %) selected-keypair-uid)
%)
keypairs)
primary-keypair? (= selected-keypair-uid (:key-uid (first keypairs)))
create-new-keypair-account #(rf/dispatch
[:wallet/add-keypair-and-create-account
{:sha3-pwd (security/safe-unmask-data %)
:new-keypair
(create-account.utils/prepare-new-keypair
{:new-keypair new-keypair
:address address
:account-name @account-name
:account-color @account-color
:emoji @emoji
:derivation-path
derivation-path})}])
create-existing-keypair-account #(rf/dispatch [:wallet/derive-address-and-add-account
{:sha3-pwd (security/safe-unmask-data %)
:emoji @emoji
:color @account-color
:path derivation-path
:account-name @account-name}])
keypair-title (or (:keypair-name new-keypair)
(if primary-keypair?
(i18n/label :t/keypair-title
{:name (:name keypair)})
(:name keypair)))]
(rn/use-unmount #(rf/dispatch [:wallet/clear-new-keypair]))
[floating-button-page/view
{:gradient-cover? true
:footer-container-padding 0
:header-container-style {:padding-top top}
:customization-color @account-color
:header [quo/page-nav
{:type :no-title
:background :blur
:right-side [{:icon-name :i/info
:on-press show-account-origin}]
:icon-name :i/close
:on-press #(rf/dispatch [:navigate-back])}]
:footer [standard-auth/slide-button
{:size :size-48
:track-text (i18n/label :t/slide-to-create-account)
:customization-color @account-color
:on-auth-success (fn [password]
(if new-keypair
(create-new-keypair-account password)
(create-existing-keypair-account
password)))
:auth-button-label (i18n/label :t/confirm)
:disabled? (empty? @account-name)
:container-style (style/slide-button-container bottom)
:dependencies [new-keypair]}]}
[rn/view {:style style/account-avatar-container}
[quo/account-avatar
{:customization-color @account-color
:size 80
:emoji @emoji
:type :default}]
[quo/button
{:size 32
:type :grey
:background :photo
:icon-only? true
:on-press #(rf/dispatch [:emoji-picker/open
{:on-select (fn [selected-emoji]
(reset! emoji selected-emoji))}])
:container-style style/reaction-button-container}
:i/reaction]]
[quo/title-input
{:customization-color @account-color
:placeholder placeholder
:on-change-text on-change-text
:max-length constants/wallet-account-name-max-length
:blur? true
:disabled? false
:default-value @account-name
:container-style style/title-input-container}]
[quo/divider-line]
(let [placeholder (i18n/label :t/default-account-placeholder)]
(fn [{:keys [account-color account-name on-change-text]}]
[quo/title-input
{:customization-color account-color
:placeholder placeholder
:on-change-text on-change-text
:max-length constants/wallet-account-name-max-length
:blur? true
:disabled? false
:default-value account-name
:container-style style/title-input-container}])))
(defn- color-picker
[_]
(let [{window-width :width} (rn/get-window)
color-picker-style {:padding-vertical 12
:padding-left (responsiveness/iphone-11-Pro-20-pixel-from-width
window-width)}]
(fn [{:keys [account-color set-account-color]}]
[:<>
[quo/divider-line]
(let [theme (quo.theme/use-theme)]
[rn/view {:style style/color-picker-container}
[quo/text
{:size :paragraph-2
@ -165,17 +102,168 @@
:style (style/color-label theme)}
(i18n/label :t/colour)]
[quo/color-picker
{:default-selected @account-color
:on-change #(reset! account-color %)
:container-style {:padding-vertical 12
:padding-left (responsiveness/iphone-11-Pro-20-pixel-from-width
window-width)}}]]
[quo/divider-line]
[quo/category
{:list-type :settings
:label (i18n/label :t/origin)
:data (get-keypair-data {:title keypair-title
:primary-keypair? primary-keypair?
:new-keypair? (boolean new-keypair)
:derivation-path derivation-path
:customization-color customization-color})}]]))))
{:default-selected account-color
:on-change set-account-color
:container-style color-picker-style}]])])))
(defn- new-account-origin
[{:keys [keypair-title derivation-path customization-color]}]
(let [{keypair-name :name} (rf/sub [:wallet/selected-keypair])
primary? (rf/sub [:wallet/selected-primary-keypair?])
keypair-name (or keypair-title
(if primary?
(i18n/label :t/keypair-title {:name keypair-name})
keypair-name))]
[:<>
[quo/divider-line]
[quo/category
{:list-type :settings
:label (i18n/label :t/origin)
:data (get-keypair-data {:primary-keypair? primary?
:title keypair-name
:derivation-path derivation-path
:customization-color customization-color})}]]))
(defn- floating-button
[_ & _]
(let [top (safe-area/get-top)
bottom (safe-area/get-bottom)
header [quo/page-nav
{:type :no-title
:background :blur
:right-side [{:icon-name :i/info
:on-press #(rf/dispatch [:show-bottom-sheet
{:content account-origin/view}])}]
:icon-name :i/close
:on-press #(rf/dispatch [:navigate-back])}]]
(fn [{:keys [slide-button-props account-color]} & children]
(into
[floating-button-page/view
{:gradient-cover? true
:footer-container-padding 0
:header-container-style {:padding-top top}
:customization-color account-color
:header header
:footer [standard-auth/slide-button
(assoc slide-button-props
:size :size-48
:track-text (i18n/label :t/slide-to-create-account)
:customization-color account-color
:auth-button-label (i18n/label :t/confirm)
:container-style (style/slide-button-container bottom))]}]
children))))
(defn add-new-keypair-variant
[{:keys [on-change-text set-account-color set-emoji]
{:keys [account-name account-color emoji]}
:state}]
(let [on-auth-success (fn [password]
(rf/dispatch
[:wallet/import-and-create-keypair-with-account
{:password password
:account-preferences {:account-name @account-name
:color @account-color
:emoji @emoji}}]))]
(fn [{:keys [customization-color keypair-name]}]
(let [{:keys [new-account-data]} (rf/sub [:wallet/create-account-new-keypair])]
[floating-button
{:account-color @account-color
:slide-button-props {:on-auth-success on-auth-success
:disabled? (empty? @account-name)
:dependencies [new-account-data]}}
[avatar
{:account-color @account-color
:emoji @emoji
:on-select-emoji set-emoji}]
[input
{:account-color @account-color
:account-name @account-name
:on-change-text on-change-text}]
[color-picker
{:account-color @account-color
:set-account-color set-account-color}]
[new-account-origin
{:derivation-path constants/path-default-wallet
:customization-color customization-color
:keypair-title keypair-name}]]))))
(defn derive-account-variant
[{:keys [on-change-text set-account-color set-emoji]
{:keys [account-name account-color emoji]}
:state}]
(let [derivation-path (reagent/atom "")
set-derivation-path #(reset! derivation-path %)]
(fn [{:keys [customization-color]}]
(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
:derivation-path @derivation-path
:account-preferences preferences}])))
[derived-from])]
(rn/use-effect
#(rf/dispatch
[:wallet/next-derivation-path
{:on-success set-derivation-path
:keypair-uid key-uid}])
[key-uid])
[floating-button
{:account-color @account-color
:slide-button-props {:on-auth-success on-auth-success
:disabled? (or (empty? @account-name)
(= "" @derivation-path))}}
[avatar
{:account-color @account-color
:emoji @emoji
:on-select-emoji set-emoji}]
[input
{:account-color @account-color
:account-name @account-name
:on-change-text on-change-text}]
[color-picker
{:account-color @account-color
:set-account-color set-account-color}]
[new-account-origin
{:derivation-path @derivation-path
:customization-color customization-color}]]))))
(defn view
[_]
(let [account-name (reagent/atom "")
account-color (reagent/atom (rand-nth colors/account-colors))
emoji (reagent/atom (emoji-picker.utils/random-emoji))
on-change-text #(reset! account-name %)
set-account-color #(reset! account-color %)
set-emoji #(reset! emoji %)
state {:account-name account-name
:account-color account-color
:emoji emoji}]
(fn []
(let [customization-color (rf/sub [:profile/customization-color])
;; Having a keypair means the user is importing it or creating it.
{:keys [keypair-name]} (rf/sub [:wallet/create-account-new-keypair])]
(rn/use-unmount #(rf/dispatch [:wallet/clear-create-account]))
(if keypair-name
[add-new-keypair-variant
{:customization-color customization-color
:on-change-text on-change-text
:set-account-color set-account-color
:set-emoji set-emoji
:state state
:keypair-name keypair-name}]
[derive-account-variant
{:customization-color customization-color
:on-change-text on-change-text
:set-account-color set-account-color
:set-emoji set-emoji
:state state}])))))

View File

@ -2,15 +2,18 @@
(:require
[clojure.string :as string]
[native-module.core :as native-module]
[re-frame.core :as rf]))
[re-frame.core :as rf]
[taoensso.timbre :as log]))
(rf/reg-fx
:effects.wallet/create-account-from-mnemonic
(fn [{:keys [seed-phrase keypair-name]}]
(native-module/create-account-from-mnemonic
{: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)}])))))
(fn [{:keys [mnemonic-phrase paths on-success]
:or {paths []}}]
(let [phrase (condp #(%1 %2) mnemonic-phrase
string? mnemonic-phrase
coll? (string/join " " mnemonic-phrase)
(log/error "Unexpected value " mnemonic-phrase))]
(native-module/create-account-from-mnemonic
{:MnemonicPhrase phrase
:paths paths}
on-success))))

View File

@ -16,17 +16,18 @@
[utils.i18n :as i18n]
[utils.number]
[utils.re-frame :as rf]
[utils.security.core :as security]
[utils.transforms :as transforms]))
(rf/reg-event-fx :wallet/show-account-created-toast
(fn [{:keys [db]} [address]]
(let [account (get-in db [:wallet :accounts address])]
(let [account-name (get-in db [:wallet :accounts address :name])]
{:db (update db :wallet dissoc :navigate-to-account :new-account?)
:fx [[:dispatch
[:toasts/upsert
{:id :new-wallet-account-created
:type :positive
:text (i18n/label :t/account-created {:name (:name account)})}]]]})))
:text (i18n/label :t/account-created {:name account-name})}]]]})))
(rf/reg-event-fx :wallet/navigate-to-account
(fn [{:keys [db]} [address]]
@ -173,30 +174,22 @@
[{:keys [db]}]
{:db (update-in db [:wallet :ui] dissoc :scanned-address)})
(rf/reg-event-fx :wallet/create-derived-addresses
(fn [{:keys [db]} [{:keys [sha3-pwd path]} on-success]]
(let [{:keys [address]} (:profile/profile db)]
{:fx [[:json-rpc/call
[{:method "wallet_getDerivedAddresses"
:params [sha3-pwd address [path]]
:on-success on-success
:on-error #(log/info "failed to derive address " %)}]]]})))
(rf/reg-event-fx :wallet/add-account-success
(fn [{:keys [db]} [address]]
{:db (update db
:wallet assoc
:navigate-to-account address
:new-account? true)
{:db (-> db
(assoc-in [:wallet :navigate-to-account] address)
(assoc-in [:wallet :new-account?] true))
:fx [[:dispatch [:wallet/get-accounts]]
[:dispatch [:wallet/get-keypairs]]
[:dispatch [:wallet/clear-new-keypair]]]}))
[:dispatch [:wallet/clear-create-account]]]}))
(rf/reg-event-fx :wallet/add-account
(fn [{:keys [db]}
[{:keys [sha3-pwd emoji account-name color type] :or {type :generated}}
{:keys [public-key address path]}]]
(let [lowercase-address (if address (string/lower-case address) address)
[{:keys [password account-name emoji color type]
:or {type :generated}}
{:keys [public-key address path] :as _derived-account}]]
(let [lowercase-address (some-> address
(string/lower-case))
key-uid (get-in db [:wallet :ui :create-account :selected-keypair-uid])
account-config {:key-uid (when (= type :generated) key-uid)
:wallet false
@ -210,30 +203,11 @@
:colorID color}]
{:fx [[:json-rpc/call
[{:method "accounts_addAccount"
:params [(when (= type :generated) sha3-pwd) account-config]
:params [(when (= type :generated)
(security/safe-unmask-data password))
account-config]
:on-success [:wallet/add-account-success lowercase-address]
:on-error #(log/info "failed to create account " %)}]]]})))
(rf/reg-event-fx
:wallet/derive-address-and-add-account
(fn [_ [account-details]]
(let [on-success (fn [derived-address-details]
(rf/dispatch [:wallet/add-account account-details
(first derived-address-details)]))]
{:fx [[:dispatch [:wallet/create-derived-addresses account-details on-success]]]})))
(defn add-keypair-and-create-account
[_ [{:keys [sha3-pwd new-keypair]}]]
(let [lowercase-address (if (:address new-keypair)
(string/lower-case (:address new-keypair))
(:address new-keypair))]
{:fx [[:json-rpc/call
[{:method "accounts_addKeypair"
:params [sha3-pwd new-keypair]
:on-success [:wallet/add-account-success lowercase-address]
:on-error #(log/info "failed to create keypair " %)}]]]}))
(rf/reg-event-fx :wallet/add-keypair-and-create-account add-keypair-and-create-account)
:on-error #(log/info "failed to create account " % account-config)}]]]})))
(defn get-keypairs
[_]

View File

@ -47,6 +47,11 @@
:<- [:wallet/ui]
:-> :create-account)
(rf/reg-sub
:wallet/create-account-new-keypair
:<- [:wallet/create-account]
:-> :new-keypair)
(rf/reg-sub
:wallet/network-filter
:<- [:wallet/ui]
@ -165,6 +170,25 @@
:<- [:wallet/create-account]
:-> :selected-keypair-uid)
(rf/reg-sub
:wallet/selected-keypair
:<- [:wallet/keypairs]
:<- [:wallet/selected-keypair-uid]
(fn [[keypairs selected-keypair-uid]]
(some #(when (= (:key-uid %) selected-keypair-uid)
%)
keypairs)))
(rf/reg-sub
:wallet/selected-primary-keypair?
:<- [:wallet/keypairs]
:<- [:wallet/selected-keypair-uid]
(fn [[keypairs selected-keypair-uid]]
(let [primary-keypair-uid (->> keypairs
(some #(when (= (:type %) "profile") %))
(:key-uid))]
(= selected-keypair-uid primary-keypair-uid))))
(rf/reg-sub
:wallet/selected-networks->chain-ids
:<- [:wallet/selected-networks]