[#9749] Support importing private key and seed
This commit is contained in:
parent
c9486dc634
commit
a79a72fccb
|
@ -620,5 +620,6 @@ var TopLevel = {
|
||||||
"multiAccountLoadAccount" : function () {},
|
"multiAccountLoadAccount" : function () {},
|
||||||
"multiAccountStoreAccount" : function () {},
|
"multiAccountStoreAccount" : function () {},
|
||||||
"multiAccountImportMnemonic" : function () {},
|
"multiAccountImportMnemonic" : function () {},
|
||||||
|
"multiAccountImportPrivateKey" : function () {},
|
||||||
"validateMnemonic" : function () {}
|
"validateMnemonic" : function () {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -776,6 +776,23 @@ class StatusModule extends ReactContextBaseJavaModule implements LifecycleEventL
|
||||||
StatusThreadPoolExecutor.getInstance().execute(r);
|
StatusThreadPoolExecutor.getInstance().execute(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ReactMethod
|
||||||
|
public void multiAccountImportPrivateKey(final String json, final Callback callback) {
|
||||||
|
Log.d(TAG, "multiAccountImportPrivateKey");
|
||||||
|
if (!checkAvailability()) {
|
||||||
|
callback.invoke(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Runnable r = new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
String res = Statusgo.multiAccountImportPrivateKey(json);
|
||||||
|
callback.invoke(res);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
StatusThreadPoolExecutor.getInstance().execute(r);
|
||||||
|
}
|
||||||
|
|
||||||
@ReactMethod
|
@ReactMethod
|
||||||
public void hashTransaction(final String txArgsJSON, final Callback callback) {
|
public void hashTransaction(final String txArgsJSON, final Callback callback) {
|
||||||
Log.d(TAG, "hashTransaction");
|
Log.d(TAG, "hashTransaction");
|
||||||
|
|
|
@ -266,6 +266,16 @@ RCT_EXPORT_METHOD(multiAccountStoreDerived:(NSString *)json
|
||||||
callback(@[result]);
|
callback(@[result]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////// multiAccountImportPrivateKey
|
||||||
|
RCT_EXPORT_METHOD(multiAccountImportPrivateKey:(NSString *)json
|
||||||
|
callback:(RCTResponseSenderBlock)callback) {
|
||||||
|
#if DEBUG
|
||||||
|
NSLog(@"MultiAccountImportPrivateKey() method called");
|
||||||
|
#endif
|
||||||
|
NSString *result = StatusgoMultiAccountImportPrivateKey(json);
|
||||||
|
callback(@[result]);
|
||||||
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////// multiAccountImportMnemonic
|
//////////////////////////////////////////////////////////////////// multiAccountImportMnemonic
|
||||||
RCT_EXPORT_METHOD(multiAccountImportMnemonic:(NSString *)json
|
RCT_EXPORT_METHOD(multiAccountImportMnemonic:(NSString *)json
|
||||||
callback:(RCTResponseSenderBlock)callback) {
|
callback:(RCTResponseSenderBlock)callback) {
|
||||||
|
|
|
@ -18,13 +18,11 @@
|
||||||
(if card-connected?
|
(if card-connected?
|
||||||
(fx/merge cofx
|
(fx/merge cofx
|
||||||
{:db (assoc-in db [:hardwallet :on-export-success]
|
{:db (assoc-in db [:hardwallet :on-export-success]
|
||||||
#(vector :wallet.accounts/account-generated
|
#(vector :wallet.accounts/account-stored
|
||||||
{:name (str "Account " path-num)
|
{;; Strip leading 04 prefix denoting uncompressed key format
|
||||||
;; Strip leading 04 prefix denoting uncompressed key format
|
|
||||||
:address (eip55/address->checksum (str "0x" (ethereum/public-key->address (subs % 2))))
|
:address (eip55/address->checksum (str "0x" (ethereum/public-key->address (subs % 2))))
|
||||||
:public-key (str "0x" %)
|
:public-key (str "0x" %)
|
||||||
:path path
|
:path path}))
|
||||||
:color (rand-nth colors/account-colors)}))
|
|
||||||
:hardwallet/export-key {:pin pin :pairing pairing :path path}}
|
:hardwallet/export-key {:pin pin :pairing pairing :path path}}
|
||||||
(navigation/navigate-to-cofx :keycard-processing nil)
|
(navigation/navigate-to-cofx :keycard-processing nil)
|
||||||
(common/set-on-card-connected :wallet.accounts/generate-new-keycard-account))
|
(common/set-on-card-connected :wallet.accounts/generate-new-keycard-account))
|
||||||
|
|
|
@ -157,9 +157,15 @@
|
||||||
(types/clj->json {:mnemonicPhrase mnemonic
|
(types/clj->json {:mnemonicPhrase mnemonic
|
||||||
;;NOTE this is not the multiaccount password
|
;;NOTE this is not the multiaccount password
|
||||||
:Bip39Passphrase password})
|
:Bip39Passphrase password})
|
||||||
|
|
||||||
callback))
|
callback))
|
||||||
|
|
||||||
|
(defn multiaccount-import-private-key
|
||||||
|
[private-key callback]
|
||||||
|
(log/debug "[native-module] multiaccount-import-private-key")
|
||||||
|
(.multiAccountImportPrivateKey (status)
|
||||||
|
(types/clj->json {:privateKey private-key})
|
||||||
|
callback))
|
||||||
|
|
||||||
(defn verify
|
(defn verify
|
||||||
"NOTE: beware, the password has to be sha3 hashed"
|
"NOTE: beware, the password has to be sha3 hashed"
|
||||||
[address hashed-password callback]
|
[address hashed-password callback]
|
||||||
|
|
|
@ -538,15 +538,19 @@
|
||||||
:add-account-disabled?
|
:add-account-disabled?
|
||||||
:<- [:multiaccount/accounts]
|
:<- [:multiaccount/accounts]
|
||||||
:<- [:add-account]
|
:<- [:add-account]
|
||||||
(fn [[accounts {:keys [address]}]]
|
(fn [[accounts {:keys [address type account seed private-key]}]]
|
||||||
(or (not (ethereum/address? address))
|
(or (string/blank? (:name account))
|
||||||
(some #(when (= (:address %) address) %) accounts))))
|
(case type
|
||||||
|
:generate
|
||||||
(re-frame/reg-sub
|
false
|
||||||
:add-account-scanned-address
|
:watch
|
||||||
:<- [:add-account]
|
(or (not (ethereum/address? address))
|
||||||
(fn [add-account]
|
(some #(when (= (:address %) address) %) accounts))
|
||||||
(get add-account :scanned-address)))
|
:key
|
||||||
|
(string/blank? (security/safe-unmask-data private-key))
|
||||||
|
:seed
|
||||||
|
(string/blank? (security/safe-unmask-data seed))
|
||||||
|
false))))
|
||||||
|
|
||||||
;;CHAT ==============================================================================================================
|
;;CHAT ==============================================================================================================
|
||||||
|
|
||||||
|
|
|
@ -8,8 +8,6 @@
|
||||||
:new-public-chat :default
|
:new-public-chat :default
|
||||||
:wallet-account :default
|
:wallet-account :default
|
||||||
:add-new-account :default
|
:add-new-account :default
|
||||||
:add-watch-account :default
|
|
||||||
:add-new-account-password :default
|
|
||||||
:add-new-account-pin :default
|
:add-new-account-pin :default
|
||||||
:about-app :default
|
:about-app :default
|
||||||
:help-center :default
|
:help-center :default
|
||||||
|
|
|
@ -184,10 +184,7 @@
|
||||||
:welcome [:modal home/welcome]
|
:welcome [:modal home/welcome]
|
||||||
:keycard-welcome keycard/welcome
|
:keycard-welcome keycard/welcome
|
||||||
:add-new-account add-account/add-account
|
:add-new-account add-account/add-account
|
||||||
:add-watch-account add-account/add-watch-account
|
|
||||||
:add-new-account-password add-account/password
|
|
||||||
:add-new-account-pin add-account/pin
|
:add-new-account-pin add-account/pin
|
||||||
:account-added account-settings/account-added
|
|
||||||
:account-settings account-settings/account-settings})
|
:account-settings account-settings/account-settings})
|
||||||
|
|
||||||
(defn get-screen [screen]
|
(defn get-screen [screen]
|
||||||
|
|
|
@ -6,10 +6,7 @@
|
||||||
:screens (cond-> [:wallet
|
:screens (cond-> [:wallet
|
||||||
:wallet-account
|
:wallet-account
|
||||||
:add-new-account
|
:add-new-account
|
||||||
:add-watch-account
|
|
||||||
:add-new-account-password
|
|
||||||
:add-new-account-pin
|
:add-new-account-pin
|
||||||
:account-added
|
|
||||||
:account-settings
|
:account-settings
|
||||||
:collectibles-list
|
:collectibles-list
|
||||||
:wallet-onboarding-setup
|
:wallet-onboarding-setup
|
||||||
|
|
|
@ -6,8 +6,6 @@
|
||||||
[status-im.i18n :as i18n]
|
[status-im.i18n :as i18n]
|
||||||
[status-im.ui.components.icons.vector-icons :as icons]
|
[status-im.ui.components.icons.vector-icons :as icons]
|
||||||
[status-im.ui.components.colors :as colors]
|
[status-im.ui.components.colors :as colors]
|
||||||
[status-im.ui.components.button :as button]
|
|
||||||
[clojure.string :as string]
|
|
||||||
[status-im.ui.components.toolbar :as toolbar]
|
[status-im.ui.components.toolbar :as toolbar]
|
||||||
[status-im.ui.components.copyable-text :as copyable-text]
|
[status-im.ui.components.copyable-text :as copyable-text]
|
||||||
[reagent.core :as reagent]
|
[reagent.core :as reagent]
|
||||||
|
@ -33,45 +31,6 @@
|
||||||
:label (i18n/label :t/cancel)
|
:label (i18n/label :t/cancel)
|
||||||
:type :secondary}}]]))
|
:type :secondary}}]]))
|
||||||
|
|
||||||
(defview account-added []
|
|
||||||
(letsubs [{:keys [account]} [:add-account]]
|
|
||||||
[react/keyboard-avoiding-view {:flex 1}
|
|
||||||
[react/scroll-view {:keyboard-should-persist-taps :handled
|
|
||||||
:style {:margin-top 70 :flex 1}}
|
|
||||||
[react/view {:align-items :center :padding-horizontal 40}
|
|
||||||
[react/view {:height 40 :width 40 :border-radius 20 :align-items :center :justify-content :center
|
|
||||||
:background-color (:color account)}
|
|
||||||
[icons/icon :main-icons/check {:color colors/white}]]
|
|
||||||
[react/text {:style {:typography :header :margin-top 16}}
|
|
||||||
(i18n/label :t/account-added)]
|
|
||||||
[react/text {:style {:color colors/gray :text-align :center :margin-top 16 :line-height 22}}
|
|
||||||
(i18n/label :t/you-can-change-account)]]
|
|
||||||
[react/view {:height 52}]
|
|
||||||
[react/view {:margin-horizontal 16}
|
|
||||||
[text-input/text-input-with-label
|
|
||||||
{:label (i18n/label :t/account-name)
|
|
||||||
:auto-focus false
|
|
||||||
:default-value (:name account)
|
|
||||||
:placeholder (i18n/label :t/account-name)
|
|
||||||
:on-change-text #(re-frame/dispatch [:set-in [:add-account :account :name] %])}]
|
|
||||||
[react/text {:style {:margin-top 30}} (i18n/label :t/account-color)]
|
|
||||||
[react/touchable-highlight
|
|
||||||
{:on-press #(re-frame/dispatch [:show-popover
|
|
||||||
{:view [colors-popover (:color account)
|
|
||||||
(fn [new-color]
|
|
||||||
(re-frame/dispatch [:set-in [:add-account :account :color] new-color])
|
|
||||||
(re-frame/dispatch [:hide-popover]))]
|
|
||||||
:style {:max-height "60%"}}])}
|
|
||||||
[react/view {:height 52 :margin-top 12 :background-color (:color account) :border-radius 8
|
|
||||||
:align-items :flex-end :justify-content :center :padding-right 12}
|
|
||||||
[icons/icon :main-icons/dropdown {:color colors/white}]]]]]
|
|
||||||
[toolbar/toolbar
|
|
||||||
{:show-border? true
|
|
||||||
:right {:type :next
|
|
||||||
:label (i18n/label :t/finish)
|
|
||||||
:on-press #(re-frame/dispatch [:wallet.accounts/save-generated-account])
|
|
||||||
:disabled? (string/blank? (:name account))}}]]))
|
|
||||||
|
|
||||||
(defn property [label value]
|
(defn property [label value]
|
||||||
[react/view {:margin-top 28}
|
[react/view {:margin-top 28}
|
||||||
[react/text {:style {:color colors/gray}} label]
|
[react/text {:style {:color colors/gray}} label]
|
||||||
|
@ -118,6 +77,7 @@
|
||||||
[property (i18n/label :t/type)
|
[property (i18n/label :t/type)
|
||||||
(case type
|
(case type
|
||||||
:watch (i18n/label :t/watch-only)
|
:watch (i18n/label :t/watch-only)
|
||||||
|
(:key :seed) (i18n/label :t/off-status-tree)
|
||||||
(i18n/label :t/on-status-tree))]
|
(i18n/label :t/on-status-tree))]
|
||||||
[property (i18n/label :t/wallet-address)
|
[property (i18n/label :t/wallet-address)
|
||||||
[copyable-text/copyable-text-view
|
[copyable-text/copyable-text-view
|
||||||
|
|
|
@ -15,25 +15,29 @@
|
||||||
:title :t/wallet-manage-assets
|
:title :t/wallet-manage-assets
|
||||||
:icon :main-icons/token
|
:icon :main-icons/token
|
||||||
:accessibility-label :wallet-manage-assets
|
:accessibility-label :wallet-manage-assets
|
||||||
:on-press #(hide-sheet-and-dispatch [:navigate-to :wallet-settings-assets])}]
|
:on-press #(hide-sheet-and-dispatch
|
||||||
|
[:navigate-to :wallet-settings-assets])}]
|
||||||
[list-item/list-item
|
[list-item/list-item
|
||||||
{:theme :action
|
{:theme :action
|
||||||
:title :t/set-currency
|
:title :t/set-currency
|
||||||
:icon :main-icons/language
|
:icon :main-icons/language
|
||||||
:accessibility-label :wallet-set-currency
|
:accessibility-label :wallet-set-currency
|
||||||
:on-press #(hide-sheet-and-dispatch [:navigate-to :currency-settings])}]
|
:on-press #(hide-sheet-and-dispatch
|
||||||
|
[:navigate-to :currency-settings])}]
|
||||||
[list-item/list-item
|
[list-item/list-item
|
||||||
{:theme :action
|
{:theme :action
|
||||||
:title :t/view-signing
|
:title :t/view-signing
|
||||||
:icon :main-icons/info
|
:icon :main-icons/info
|
||||||
:on-press #(hide-sheet-and-dispatch [:show-popover {:view :signing-phrase}])}]
|
:on-press #(hide-sheet-and-dispatch
|
||||||
|
[:show-popover {:view :signing-phrase}])}]
|
||||||
(when mnemonic
|
(when mnemonic
|
||||||
[list-item/list-item
|
[list-item/list-item
|
||||||
{:theme :action-destructive
|
{:theme :action-destructive
|
||||||
:title :t/wallet-backup-recovery-title
|
:title :t/wallet-backup-recovery-title
|
||||||
:icon :main-icons/security
|
:icon :main-icons/security
|
||||||
:accessibility-label :wallet-backup-recovery-title
|
:accessibility-label :wallet-backup-recovery-title
|
||||||
:on-press #(hide-sheet-and-dispatch [:navigate-to :backup-seed])}])]))
|
:on-press #(hide-sheet-and-dispatch
|
||||||
|
[:navigate-to :backup-seed])}])]))
|
||||||
|
|
||||||
(defn send-receive [account type]
|
(defn send-receive [account type]
|
||||||
[react/view
|
[react/view
|
||||||
|
@ -43,7 +47,8 @@
|
||||||
:title :t/wallet-send
|
:title :t/wallet-send
|
||||||
:icon :main-icons/send
|
:icon :main-icons/send
|
||||||
:accessibility-label :send-transaction-button
|
:accessibility-label :send-transaction-button
|
||||||
:on-press #(hide-sheet-and-dispatch [:wallet/prepare-transaction-from-wallet account])}])
|
:on-press #(hide-sheet-and-dispatch
|
||||||
|
[:wallet/prepare-transaction-from-wallet account])}])
|
||||||
[list-item/list-item
|
[list-item/list-item
|
||||||
{:theme :action
|
{:theme :action
|
||||||
:title :t/receive
|
:title :t/receive
|
||||||
|
@ -56,27 +61,40 @@
|
||||||
(defn add-account []
|
(defn add-account []
|
||||||
[react/view
|
[react/view
|
||||||
[list-item/list-item
|
[list-item/list-item
|
||||||
{:theme :action
|
{:title :t/generate-a-new-account
|
||||||
:title :t/add-an-account
|
:theme :action
|
||||||
:icon :main-icons/add
|
:icon :main-icons/add
|
||||||
:on-press #(hide-sheet-and-dispatch [:navigate-to :add-new-account])}]
|
:on-press #(hide-sheet-and-dispatch
|
||||||
|
[:wallet.accounts/start-adding-new-account
|
||||||
|
{:type :generate}])}]
|
||||||
[list-item/list-item
|
[list-item/list-item
|
||||||
{:theme :action
|
{:theme :action
|
||||||
:title :t/add-a-watch-account
|
:title :t/add-a-watch-account
|
||||||
:icon :main-icons/watch
|
:icon :main-icons/watch
|
||||||
:on-press #(hide-sheet-and-dispatch [:wallet.accounts/start-adding-new-account {:type :watch}])}]])
|
:on-press #(hide-sheet-and-dispatch
|
||||||
|
[:wallet.accounts/start-adding-new-account
|
||||||
|
{:type :watch}])}]
|
||||||
|
[list-item/list-item
|
||||||
|
{:title :t/enter-a-seed-phrase
|
||||||
|
:theme :action
|
||||||
|
:icon :main-icons/text
|
||||||
|
:on-press #(hide-sheet-and-dispatch
|
||||||
|
[:wallet.accounts/start-adding-new-account
|
||||||
|
{:type :seed}])}]
|
||||||
|
[list-item/list-item
|
||||||
|
{:title :t/enter-a-private-key
|
||||||
|
:theme :action
|
||||||
|
:icon :main-icons/address
|
||||||
|
:on-press #(hide-sheet-and-dispatch
|
||||||
|
[:wallet.accounts/start-adding-new-account
|
||||||
|
{:type :key}])}]])
|
||||||
|
|
||||||
(defn account-settings []
|
(defn account-settings []
|
||||||
[react/view
|
[react/view
|
||||||
[list-item/list-item
|
[list-item/list-item
|
||||||
{:theme :action
|
{:theme :action
|
||||||
:title :t/account-settings
|
:title :t/account-settings
|
||||||
:accessibility-label :account-settings-bottom-sheet
|
:accessibility-label :account-settings-bottom-sheet
|
||||||
:icon :main-icons/info
|
:icon :main-icons/info
|
||||||
:on-press #(hide-sheet-and-dispatch [:navigate-to :account-settings])}]
|
:on-press #(hide-sheet-and-dispatch
|
||||||
;; Commented out for v1
|
[:navigate-to :account-settings])}]])
|
||||||
#_[list-item/list-item
|
|
||||||
{:theme :action
|
|
||||||
:title :t/export-account
|
|
||||||
:icon :main-icons/copy
|
|
||||||
:disabled? true}]])
|
|
|
@ -45,7 +45,7 @@
|
||||||
(defn add-card []
|
(defn add-card []
|
||||||
[react/touchable-highlight {:on-press #(re-frame/dispatch [:bottom-sheet/show-sheet
|
[react/touchable-highlight {:on-press #(re-frame/dispatch [:bottom-sheet/show-sheet
|
||||||
{:content sheets/add-account
|
{:content sheets/add-account
|
||||||
:content-height 130}])}
|
:content-height 260}])}
|
||||||
[react/view {:style styles/add-card}
|
[react/view {:style styles/add-card}
|
||||||
[react/view {:width 40 :height 40 :justify-content :center :border-radius 20
|
[react/view {:width 40 :height 40 :justify-content :center :border-radius 20
|
||||||
:align-items :center :background-color colors/blue-transparent-10 :margin-bottom 8}
|
:align-items :center :background-color colors/blue-transparent-10 :margin-bottom 8}
|
||||||
|
|
|
@ -5,62 +5,19 @@
|
||||||
[status-im.i18n :as i18n]
|
[status-im.i18n :as i18n]
|
||||||
[re-frame.core :as re-frame]
|
[re-frame.core :as re-frame]
|
||||||
[status-im.ui.components.colors :as colors]
|
[status-im.ui.components.colors :as colors]
|
||||||
[status-im.ui.components.list-item.views :as list-item]
|
|
||||||
[reagent.core :as reagent]
|
[reagent.core :as reagent]
|
||||||
[cljs.spec.alpha :as spec]
|
[cljs.spec.alpha :as spec]
|
||||||
[status-im.multiaccounts.db :as multiaccounts.db]
|
[status-im.multiaccounts.db :as multiaccounts.db]
|
||||||
[status-im.ui.components.toolbar :as toolbar]
|
[status-im.ui.components.toolbar :as toolbar]
|
||||||
[status-im.ui.components.styles :as components.styles]
|
|
||||||
[status-im.ui.components.topbar :as topbar]
|
[status-im.ui.components.topbar :as topbar]
|
||||||
[status-im.utils.utils :as utils.utils]))
|
[status-im.utils.utils :as utils.utils]
|
||||||
|
[status-im.ui.components.text-input.view :as text-input]
|
||||||
(defn add-account []
|
[status-im.ui.components.icons.vector-icons :as icons]
|
||||||
[react/view {:flex 1}
|
[status-im.ui.screens.wallet.account-settings.views :as account-settings]
|
||||||
[topbar/topbar]
|
[status-im.ethereum.core :as ethereum]
|
||||||
[react/scroll-view {:keyboard-should-persist-taps :handled
|
[status-im.utils.security :as security]
|
||||||
:style {:flex 1}}
|
[clojure.string :as string]
|
||||||
[react/view {:align-items :center :padding-horizontal 40 :margin-bottom 52}
|
[status-im.utils.platform :as platform]))
|
||||||
[react/text {:style {:typography :header :margin-top 16}}
|
|
||||||
(i18n/label :t/add-an-account)]
|
|
||||||
[react/text {:style {:color colors/gray :text-align :center :margin-top 16 :line-height 22}}
|
|
||||||
(i18n/label :t/add-account-description)]]
|
|
||||||
[list-item/list-item
|
|
||||||
{:type :section-header
|
|
||||||
:title :t/default}]
|
|
||||||
[list-item/list-item
|
|
||||||
{:title :t/generate-a-new-account
|
|
||||||
:theme :action
|
|
||||||
:icon :main-icons/add
|
|
||||||
:accessories [:chevron]
|
|
||||||
:on-press #(re-frame/dispatch [:wallet.accounts/start-adding-new-account {:type :generate}])}]
|
|
||||||
;;TODO: implement adding account by seedphrase and private key
|
|
||||||
#_[list-item/list-item
|
|
||||||
{:type :section-header
|
|
||||||
:container-margin-top 24
|
|
||||||
:title (i18n/label :t/advanced)}]
|
|
||||||
#_[list-item/list-item
|
|
||||||
{:title (i18n/label :t/enter-a-seed-phrase)
|
|
||||||
:theme :action
|
|
||||||
:icon :main-icons/add
|
|
||||||
:accessories [:chevron]
|
|
||||||
:disabled? true
|
|
||||||
:on-press #(re-frame/dispatch [:wallet.accounts/start-adding-new-account {:type :seed}])}]
|
|
||||||
#_[list-item/list-item
|
|
||||||
{:title (i18n/label :t/enter-a-private-key)
|
|
||||||
:theme :action
|
|
||||||
:icon :main-icons/add
|
|
||||||
:accessories [:chevron]
|
|
||||||
:disabled? true
|
|
||||||
:on-press #(re-frame/dispatch [:wallet.accounts/start-adding-new-account {:type :key}])}]]])
|
|
||||||
|
|
||||||
(def input-container
|
|
||||||
{:flex-direction :row
|
|
||||||
:align-items :center
|
|
||||||
:border-radius components.styles/border-radius
|
|
||||||
:height 52
|
|
||||||
:margin 16
|
|
||||||
:padding-horizontal 16
|
|
||||||
:background-color colors/gray-lighter})
|
|
||||||
|
|
||||||
(defn- request-camera-permissions []
|
(defn- request-camera-permissions []
|
||||||
(let [options {:handler :wallet.add-new/qr-scanner-result}]
|
(let [options {:handler :wallet.add-new/qr-scanner-result}]
|
||||||
|
@ -76,37 +33,119 @@
|
||||||
(i18n/label :t/camera-access-error)))
|
(i18n/label :t/camera-access-error)))
|
||||||
50)}])))
|
50)}])))
|
||||||
|
|
||||||
(defview add-watch-account []
|
(defn add-account-topbar [type]
|
||||||
(letsubs [add-account-disabled? [:add-account-disabled?]
|
(let [title (case type
|
||||||
add-account-scanned-address [:add-account-scanned-address]]
|
:generate :t/generate-an-account
|
||||||
[react/keyboard-avoiding-view {:flex 1}
|
:watch :t/add-watch-account
|
||||||
[topbar/topbar {:accessories [{:icon :qr :handler #(request-camera-permissions)}]}]
|
:seed :t/add-seed-account
|
||||||
[react/view {:flex 1
|
:key :t/add-private-key-account
|
||||||
:justify-content :space-between
|
"")]
|
||||||
:align-items :center :margin-horizontal 16}
|
[topbar/topbar
|
||||||
[react/view
|
(merge {:title title}
|
||||||
[react/text {:style {:typography :header :margin-top 16}}
|
(when (= type :watch)
|
||||||
(i18n/label :t/add-a-watch-account)]
|
{:accessories [{:icon :qr
|
||||||
[react/text {:style {:color colors/gray :text-align :center :margin-vertical 16}}
|
:handler #(request-camera-permissions)}]}))]))
|
||||||
(i18n/label :t/enter-watch-account-address)]]
|
|
||||||
[react/view {:align-items :center :flex 1 :flex-direction :row}
|
(defn common-settings [account]
|
||||||
[react/text-input {:auto-focus true
|
[react/view {:margin-horizontal 16 :margin-top 30}
|
||||||
:multiline true
|
[text-input/text-input-with-label
|
||||||
:text-align :center
|
{:label (i18n/label :t/account-name)
|
||||||
:default-value add-account-scanned-address
|
:auto-focus false
|
||||||
:placeholder (i18n/label :t/enter-address)
|
:default-value (:name account)
|
||||||
:style {:typography :header :flex 1}
|
:placeholder (i18n/label :t/account-name)
|
||||||
:on-change-text #(re-frame/dispatch [:set-in [:add-account :address] %])}]]]
|
:on-change-text #(re-frame/dispatch [:set-in [:add-account :account :name] %])}]
|
||||||
|
[react/text {:style {:margin-top 30}} (i18n/label :t/account-color)]
|
||||||
|
[react/touchable-highlight
|
||||||
|
{:on-press #(re-frame/dispatch
|
||||||
|
[:show-popover
|
||||||
|
{:view [account-settings/colors-popover (:color account)
|
||||||
|
(fn [new-color]
|
||||||
|
(re-frame/dispatch [:set-in [:add-account :account :color] new-color])
|
||||||
|
(re-frame/dispatch [:hide-popover]))]
|
||||||
|
:style {:max-height "60%"}}])}
|
||||||
|
[react/view {:height 52 :margin-top 12 :background-color (:color account) :border-radius 8
|
||||||
|
:align-items :flex-end :justify-content :center :padding-right 12}
|
||||||
|
[icons/icon :main-icons/dropdown {:color colors/white}]]]])
|
||||||
|
|
||||||
|
(defn settings [{:keys [type scanned-address password-error account-error]}
|
||||||
|
entered-password]
|
||||||
|
[react/view {:margin-horizontal 16}
|
||||||
|
(if (= type :watch)
|
||||||
|
[text-input/text-input-with-label
|
||||||
|
{:label (i18n/label :t/wallet-key-title)
|
||||||
|
:auto-focus false
|
||||||
|
:default-value scanned-address
|
||||||
|
:placeholder (i18n/label :t/enter-address)
|
||||||
|
:on-change-text #(re-frame/dispatch [:set-in [:add-account :address] %])}]
|
||||||
|
[text-input/text-input-with-label
|
||||||
|
{:label (i18n/label :t/password)
|
||||||
|
:parent-container {:margin-top 30}
|
||||||
|
:auto-focus false
|
||||||
|
:placeholder (i18n/label :t/enter-your-password)
|
||||||
|
:secure-text-entry true
|
||||||
|
:text-content-type :none
|
||||||
|
:error (when password-error (i18n/label :t/add-account-incorrect-password))
|
||||||
|
:on-change-text #(do
|
||||||
|
(re-frame/dispatch [:set-in [:add-account :password-error] nil])
|
||||||
|
(reset! entered-password %))}])
|
||||||
|
(when (= type :seed)
|
||||||
|
[text-input/text-input-with-label
|
||||||
|
{:parent-container {:margin-top 30}
|
||||||
|
:label (i18n/label :t/recovery-phrase)
|
||||||
|
:auto-focus false
|
||||||
|
:placeholder (i18n/label :t/multiaccounts-recover-enter-phrase-title)
|
||||||
|
:auto-correct false
|
||||||
|
:keyboard-type "visible-password"
|
||||||
|
:multiline true
|
||||||
|
:style (when platform/android?
|
||||||
|
{:flex 1})
|
||||||
|
:height 95
|
||||||
|
:error account-error
|
||||||
|
:on-change-text
|
||||||
|
#(do
|
||||||
|
(re-frame/dispatch [:set-in [:add-account :account-error] nil])
|
||||||
|
(re-frame/dispatch [:set-in [:add-account :seed] (security/mask-data (string/lower-case %))]))}])
|
||||||
|
(when (= type :key)
|
||||||
|
[text-input/text-input-with-label
|
||||||
|
{:parent-container {:margin-top 30}
|
||||||
|
:label (i18n/label :t/private-key)
|
||||||
|
:auto-focus false
|
||||||
|
:placeholder (i18n/label :t/enter-a-private-key)
|
||||||
|
:auto-correct false
|
||||||
|
:keyboard-type "visible-password"
|
||||||
|
:error account-error
|
||||||
|
:secure-text-entry true
|
||||||
|
:text-content-type :none
|
||||||
|
:on-change-text
|
||||||
|
#(do
|
||||||
|
(re-frame/dispatch [:set-in [:add-account :account-error] nil])
|
||||||
|
(re-frame/dispatch [:set-in [:add-account :private-key] (security/mask-data %)]))}])])
|
||||||
|
|
||||||
|
(defview add-account []
|
||||||
|
(letsubs [{:keys [type account] :as add-account} [:add-account]
|
||||||
|
add-account-disabled? [:add-account-disabled?]
|
||||||
|
entered-password (reagent/atom "")]
|
||||||
|
[react/keyboard-avoiding-view {:style {:flex 1}}
|
||||||
|
[add-account-topbar type]
|
||||||
|
[react/scroll-view {:keyboard-should-persist-taps :handled
|
||||||
|
:style {:flex 1}}
|
||||||
|
[settings add-account entered-password]
|
||||||
|
[common-settings account]]
|
||||||
[toolbar/toolbar
|
[toolbar/toolbar
|
||||||
{:show-border? true
|
{:show-border? true
|
||||||
:right {:type :next
|
:right
|
||||||
:label (i18n/label :t/next)
|
{:type :next
|
||||||
:on-press #(re-frame/dispatch [:wallet.accounts/add-watch-account])
|
:label :t/add-account
|
||||||
:disabled? add-account-disabled?}}]]))
|
:on-press #(re-frame/dispatch [:wallet.accounts/add-new-account
|
||||||
|
(ethereum/sha3 @entered-password)])
|
||||||
|
:disabled? (or add-account-disabled?
|
||||||
|
(and
|
||||||
|
(not (= type :watch))
|
||||||
|
(not (spec/valid? ::multiaccounts.db/password @entered-password))))}}]]))
|
||||||
|
|
||||||
(defview pin []
|
(defview pin []
|
||||||
(letsubs [pin [:hardwallet/pin]
|
(letsubs [pin [:hardwallet/pin]
|
||||||
status [:hardwallet/pin-status]
|
status [:hardwallet/pin-status]
|
||||||
error-label [:hardwallet/pin-error-label]]
|
error-label [:hardwallet/pin-error-label]]
|
||||||
[react/keyboard-avoiding-view {:style {:flex 1}}
|
[react/keyboard-avoiding-view {:style {:flex 1}}
|
||||||
[topbar/topbar]
|
[topbar/topbar]
|
||||||
|
@ -116,32 +155,4 @@
|
||||||
:title-label :t/current-pin
|
:title-label :t/current-pin
|
||||||
:description-label :t/current-pin-description
|
:description-label :t/current-pin-description
|
||||||
:error-label error-label
|
:error-label error-label
|
||||||
:step :export-key}]]))
|
:step :export-key}]]))
|
||||||
|
|
||||||
(defview password []
|
|
||||||
(letsubs [{:keys [error]} [:add-account]
|
|
||||||
entered-password (reagent/atom "")]
|
|
||||||
[react/keyboard-avoiding-view {:style {:flex 1}}
|
|
||||||
[topbar/topbar]
|
|
||||||
[react/view {:flex 1
|
|
||||||
:justify-content :space-between
|
|
||||||
:align-items :center :margin-horizontal 16}
|
|
||||||
[react/text {:style {:typography :header :margin-top 16}} (i18n/label :t/enter-your-password)]
|
|
||||||
[react/view {:justify-content :center :flex 1}
|
|
||||||
[react/text-input {:secure-text-entry true
|
|
||||||
:auto-focus true
|
|
||||||
:auto-capitalize :none
|
|
||||||
:text-align :center
|
|
||||||
:placeholder ""
|
|
||||||
:style {:typography :header}
|
|
||||||
:on-change-text #(reset! entered-password %)}]
|
|
||||||
(when error
|
|
||||||
[react/text {:style {:text-align :center :color colors/red :margin-top 76}} error])]
|
|
||||||
[react/text {:style {:color colors/gray :text-align :center :margin-bottom 16}}
|
|
||||||
(i18n/label :t/to-encrypt-enter-password)]]
|
|
||||||
[toolbar/toolbar
|
|
||||||
{:show-border? true
|
|
||||||
:right {:type :next
|
|
||||||
:label :t/generate-account
|
|
||||||
:on-press #(re-frame/dispatch [:wallet.accounts/generate-new-account @entered-password])
|
|
||||||
:disabled? (not (spec/valid? ::multiaccounts.db/password @entered-password))}}]]))
|
|
|
@ -13,78 +13,228 @@
|
||||||
[status-im.ui.screens.navigation :as navigation]
|
[status-im.ui.screens.navigation :as navigation]
|
||||||
[status-im.utils.fx :as fx]
|
[status-im.utils.fx :as fx]
|
||||||
[status-im.utils.types :as types]
|
[status-im.utils.types :as types]
|
||||||
[status-im.wallet.core :as wallet]))
|
[status-im.wallet.core :as wallet]
|
||||||
|
[clojure.string :as string]
|
||||||
|
[status-im.utils.security :as security]
|
||||||
|
[status-im.multiaccounts.recover.core :as recover]
|
||||||
|
[status-im.ethereum.mnemonic :as mnemonic]))
|
||||||
|
|
||||||
|
(fx/defn start-adding-new-account
|
||||||
|
{:events [:wallet.accounts/start-adding-new-account]}
|
||||||
|
[{:keys [db] :as cofx} {:keys [type] :as add-account}]
|
||||||
|
(let [{:keys [latest-derived-path]} (:multiaccount db)
|
||||||
|
path-num (inc latest-derived-path)
|
||||||
|
account (merge
|
||||||
|
{:color (rand-nth colors/account-colors)}
|
||||||
|
(when (= type :generate)
|
||||||
|
{:name (str "Account " path-num)}))]
|
||||||
|
(fx/merge cofx
|
||||||
|
{:db (assoc db :add-account (assoc add-account :account account))}
|
||||||
|
(navigation/navigate-to-cofx :add-new-account nil))))
|
||||||
|
|
||||||
|
(fx/defn new-account-error
|
||||||
|
{:events [::new-account-error]}
|
||||||
|
[{:keys [db]} error-key error]
|
||||||
|
{:db (update db :add-account merge {error-key error
|
||||||
|
:step nil})})
|
||||||
|
|
||||||
|
(defn account-stored [path type]
|
||||||
|
(fn [result]
|
||||||
|
(let [{:keys [error publicKey address]} (types/json->clj result)]
|
||||||
|
(if error
|
||||||
|
(re-frame/dispatch [::new-account-error :account-error error])
|
||||||
|
(re-frame/dispatch [:wallet.accounts/account-stored
|
||||||
|
{:address address
|
||||||
|
:public-key publicKey
|
||||||
|
:type type
|
||||||
|
:path path}])))))
|
||||||
|
|
||||||
|
(def dec-pass-error "could not decrypt key with given password")
|
||||||
|
|
||||||
|
(defn normalize-path [path]
|
||||||
|
(if (string/starts-with? path "m/")
|
||||||
|
(str constants/path-wallet-root
|
||||||
|
"/" (last (string/split path "/")))
|
||||||
|
path))
|
||||||
|
|
||||||
|
(defn derive-and-store-account [path hashed-password type]
|
||||||
|
(fn [value]
|
||||||
|
(let [{:keys [id error]} (types/json->clj value)]
|
||||||
|
(if error
|
||||||
|
(re-frame/dispatch [::new-account-error :password-error error])
|
||||||
|
(status/multiaccount-derive-addresses
|
||||||
|
id
|
||||||
|
[path]
|
||||||
|
(fn [_]
|
||||||
|
(status/multiaccount-store-derived
|
||||||
|
id
|
||||||
|
[path]
|
||||||
|
hashed-password
|
||||||
|
(fn [result]
|
||||||
|
(let [{:keys [error] :as result} (types/json->clj result)
|
||||||
|
{:keys [publicKey address]} (get result (keyword path))]
|
||||||
|
(if error
|
||||||
|
(re-frame/dispatch [::new-account-error :account-error error])
|
||||||
|
(re-frame/dispatch
|
||||||
|
[:wallet.accounts/account-stored
|
||||||
|
{:address address
|
||||||
|
:public-key publicKey
|
||||||
|
:type type
|
||||||
|
:path (normalize-path path)}])))))))))))
|
||||||
|
|
||||||
|
(def pass-error "cannot retrieve a valid key for a given account: could not decrypt key with given password")
|
||||||
|
|
||||||
|
(defn store-account [path hashed-password type]
|
||||||
|
(fn [value]
|
||||||
|
(let [{:keys [id error]} (types/json->clj value)]
|
||||||
|
(if error
|
||||||
|
(re-frame/dispatch [::new-account-error
|
||||||
|
(if (= error pass-error) :password-error :account-error)
|
||||||
|
error])
|
||||||
|
(status/multiaccount-store-account
|
||||||
|
id
|
||||||
|
hashed-password
|
||||||
|
(account-stored path type))))))
|
||||||
|
|
||||||
(re-frame/reg-fx
|
(re-frame/reg-fx
|
||||||
:list.selection/open-share
|
::verify-password
|
||||||
(fn [obj]
|
(fn [{:keys [address hashed-password]}]
|
||||||
(list-selection/open-share obj)))
|
(status/verify
|
||||||
|
address hashed-password
|
||||||
|
#(re-frame/dispatch [:wallet.accounts/add-new-account-password-verifyied % hashed-password]))))
|
||||||
|
|
||||||
(re-frame/reg-fx
|
(re-frame/reg-fx
|
||||||
::generate-account
|
::generate-account
|
||||||
(fn [{:keys [derivation-info hashed-password path-num]}]
|
(fn [{:keys [derivation-info hashed-password]}]
|
||||||
(let [{:keys [address path]} derivation-info]
|
(let [{:keys [address path]} derivation-info]
|
||||||
(status/multiaccount-load-account
|
(status/multiaccount-load-account
|
||||||
address
|
address
|
||||||
hashed-password
|
hashed-password
|
||||||
(fn [value]
|
(derive-and-store-account path hashed-password :generated)))))
|
||||||
(let [{:keys [id error]} (types/json->clj value)]
|
|
||||||
(if error
|
|
||||||
(re-frame/dispatch [::generate-new-account-error])
|
|
||||||
(status/multiaccount-derive-addresses
|
|
||||||
id
|
|
||||||
[path]
|
|
||||||
(fn [result]
|
|
||||||
(status/multiaccount-store-derived
|
|
||||||
id
|
|
||||||
[path]
|
|
||||||
hashed-password
|
|
||||||
(fn [result]
|
|
||||||
(let [{:keys [publicKey address]}
|
|
||||||
(get (types/json->clj result) (keyword path))]
|
|
||||||
(re-frame/dispatch [:wallet.accounts/account-generated
|
|
||||||
{:name (str "Account " path-num)
|
|
||||||
:address address
|
|
||||||
:public-key publicKey
|
|
||||||
:path (str constants/path-wallet-root "/" path-num)
|
|
||||||
:color (rand-nth colors/account-colors)}])))))))))))))
|
|
||||||
|
|
||||||
(fx/defn set-symbol-request
|
(re-frame/reg-fx
|
||||||
{:events [:wallet.accounts/share]}
|
::import-account-seed
|
||||||
[_ address]
|
(fn [{:keys [passphrase hashed-password]}]
|
||||||
{:list.selection/open-share {:message (eip55/address->checksum address)}})
|
(status/multiaccount-import-mnemonic
|
||||||
|
(mnemonic/sanitize-passphrase (security/unmask passphrase))
|
||||||
|
""
|
||||||
|
(derive-and-store-account constants/path-default-wallet hashed-password :seed))))
|
||||||
|
|
||||||
|
(re-frame/reg-fx
|
||||||
|
::import-account-private-key
|
||||||
|
(fn [{:keys [private-key hashed-password]}]
|
||||||
|
(status/multiaccount-import-private-key
|
||||||
|
(string/trim (security/unmask private-key))
|
||||||
|
(store-account constants/path-default-wallet hashed-password :key))))
|
||||||
|
|
||||||
(fx/defn generate-new-account
|
(fx/defn generate-new-account
|
||||||
{:events [:wallet.accounts/generate-new-account]}
|
[{:keys [db]} hashed-password]
|
||||||
[{:keys [db]} password]
|
|
||||||
(let [wallet-root-address (get-in db [:multiaccount :wallet-root-address])
|
(let [wallet-root-address (get-in db [:multiaccount :wallet-root-address])
|
||||||
path-num (inc (get-in db [:multiaccount :latest-derived-path]))]
|
path-num (inc (get-in db [:multiaccount :latest-derived-path]))]
|
||||||
(when-not (get-in db [:add-account :step])
|
{:db (assoc-in db [:add-account :step] :generating)
|
||||||
{:db (assoc-in db [:add-account :step] :generating)
|
::generate-account {:derivation-info (if wallet-root-address
|
||||||
::generate-account {:derivation-info (if wallet-root-address
|
;; Use the walllet-root-address for stored on disk keys
|
||||||
;; Use the walllet-root-address for stored on disk keys
|
;; This needs to be the RELATIVE path to the key used to derive
|
||||||
;; This needs to be the RELATIVE path to the key used to derive
|
{:path (str "m/" path-num)
|
||||||
{:path (str "m/" path-num)
|
:address wallet-root-address}
|
||||||
:address wallet-root-address}
|
;; Fallback on the master account for keycards, use the absolute path
|
||||||
;; Fallback on the master account for keycards, use the absolute path
|
{:path (str constants/path-wallet-root "/" path-num)
|
||||||
{:path (str constants/path-wallet-root "/" path-num)
|
:address (get-in db [:multiaccount :address])})
|
||||||
:address (get-in db [:multiaccount :address])})
|
:hashed-password hashed-password}}))
|
||||||
:path-num path-num
|
|
||||||
:hashed-password (ethereum/sha3 password)}})))
|
|
||||||
|
|
||||||
(fx/defn generate-new-account-error
|
(fx/defn import-new-account-seed
|
||||||
{:events [::generate-new-account-error]}
|
[{:keys [db]} passphrase hashed-password]
|
||||||
[{:keys [db]} password]
|
{:db (assoc-in db [:add-account :step] :generating)
|
||||||
{:db (assoc db
|
::recover/validate-mnemonic [(security/safe-unmask-data passphrase)
|
||||||
:add-account
|
#(re-frame/dispatch [:wallet.accounts/seed-validated
|
||||||
{:error (i18n/label :t/add-account-incorrect-password)})})
|
% passphrase hashed-password])]})
|
||||||
|
|
||||||
|
(fx/defn new-account-seed-validated
|
||||||
|
{:events [:wallet.accounts/seed-validated]}
|
||||||
|
[cofx phrase-warnings passphrase hashed-password]
|
||||||
|
(let [error (:error (types/json->clj phrase-warnings))]
|
||||||
|
(if-not (string/blank? error)
|
||||||
|
(new-account-error cofx :account-error error)
|
||||||
|
{::import-account-seed {:passphrase passphrase
|
||||||
|
:hashed-password hashed-password}})))
|
||||||
|
|
||||||
|
(fx/defn import-new-account-private-key
|
||||||
|
[{:keys [db]} private-key hashed-password]
|
||||||
|
{:db (assoc-in db [:add-account :step] :generating)
|
||||||
|
::import-account-private-key {:private-key private-key
|
||||||
|
:hashed-password hashed-password}})
|
||||||
|
|
||||||
|
(fx/defn save-new-account
|
||||||
|
[{:keys [db] :as cofx}]
|
||||||
|
(let [{:keys [latest-derived-path]} (:multiaccount db)
|
||||||
|
{:keys [account type]} (:add-account db)
|
||||||
|
accounts (:multiaccount/accounts db)
|
||||||
|
new-accounts (conj accounts account)]
|
||||||
|
(when account
|
||||||
|
(fx/merge cofx
|
||||||
|
{::json-rpc/call [{:method "accounts_saveAccounts"
|
||||||
|
:params [[account]]
|
||||||
|
:on-success #()}]
|
||||||
|
:db (-> db
|
||||||
|
(assoc :multiaccount/accounts new-accounts)
|
||||||
|
(dissoc :add-account))}
|
||||||
|
(when (= type :generate)
|
||||||
|
(multiaccounts.update/multiaccount-update
|
||||||
|
:latest-derived-path (inc latest-derived-path)
|
||||||
|
{}))))))
|
||||||
|
|
||||||
(fx/defn account-generated
|
(fx/defn account-generated
|
||||||
{:events [:wallet.accounts/account-generated]}
|
{:events [:wallet.accounts/account-stored]}
|
||||||
[{:keys [db] :as cofx} account]
|
[{:keys [db] :as cofx} {:keys [address] :as account}]
|
||||||
(fx/merge cofx
|
(let [accounts (:multiaccount/accounts db)]
|
||||||
{:db (update db :add-account assoc :account account :step :generated)}
|
(if (some #(when (= (:address %) address) %) accounts)
|
||||||
(navigation/navigate-to-cofx :account-added nil)))
|
(new-account-error cofx :account-error (i18n/label :t/account-exists-title))
|
||||||
|
(fx/merge cofx
|
||||||
|
{:db (update-in db [:add-account :account] merge account)}
|
||||||
|
(save-new-account)
|
||||||
|
(wallet/update-balances nil)
|
||||||
|
(wallet/update-prices)
|
||||||
|
(navigation/navigate-back)))))
|
||||||
|
|
||||||
|
(fx/defn add-watch-account
|
||||||
|
[{:keys [db] :as cofx}]
|
||||||
|
(let [address (get-in db [:add-account :address])]
|
||||||
|
(account-generated cofx {:address (eip55/address->checksum (ethereum/normalized-hex address))
|
||||||
|
:type :watch})))
|
||||||
|
|
||||||
|
(fx/defn add-new-account-password-verifyied
|
||||||
|
{:events [:wallet.accounts/add-new-account-password-verifyied]}
|
||||||
|
[{:keys [db] :as cofx} result hashed-password]
|
||||||
|
(let [{:keys [error]} (types/json->clj result)]
|
||||||
|
(if (not (string/blank? error))
|
||||||
|
(new-account-error cofx :password-error error)
|
||||||
|
(let [{:keys [type step seed private-key]} (:add-account db)]
|
||||||
|
(case type
|
||||||
|
:seed
|
||||||
|
(import-new-account-seed cofx seed hashed-password)
|
||||||
|
:key
|
||||||
|
(import-new-account-private-key cofx private-key hashed-password)
|
||||||
|
nil)))))
|
||||||
|
|
||||||
|
(fx/defn add-new-account-verify-password
|
||||||
|
[{:keys [db]} hashed-password]
|
||||||
|
{:db (assoc-in db [:add-account :step] :generating)
|
||||||
|
::verify-password {:address (get-in db [:multiaccount :wallet-root-address])
|
||||||
|
:hashed-password hashed-password}})
|
||||||
|
|
||||||
|
(fx/defn add-new-account
|
||||||
|
{:events [:wallet.accounts/add-new-account]}
|
||||||
|
[{:keys [db] :as cofx} hashed-password]
|
||||||
|
(let [{:keys [type step]} (:add-account db)]
|
||||||
|
(when-not step
|
||||||
|
(case type
|
||||||
|
:watch
|
||||||
|
(add-watch-account cofx)
|
||||||
|
:generate
|
||||||
|
(generate-new-account cofx hashed-password)
|
||||||
|
(:seed :key)
|
||||||
|
(add-new-account-verify-password cofx hashed-password)
|
||||||
|
nil))))
|
||||||
|
|
||||||
(fx/defn save-account
|
(fx/defn save-account
|
||||||
{:events [:wallet.accounts/save-account]}
|
{:events [:wallet.accounts/save-account]}
|
||||||
|
@ -114,63 +264,6 @@
|
||||||
(assoc-in [:wallet :accounts deleted-address] nil))}
|
(assoc-in [:wallet :accounts deleted-address] nil))}
|
||||||
(navigation/navigate-to-cofx :wallet nil))))
|
(navigation/navigate-to-cofx :wallet nil))))
|
||||||
|
|
||||||
(fx/defn save-generated-account
|
|
||||||
{:events [:wallet.accounts/save-generated-account]}
|
|
||||||
[{:keys [db] :as cofx}]
|
|
||||||
(let [{:keys [latest-derived-path]} (:multiaccount db)
|
|
||||||
{:keys [account path type]} (:add-account db)
|
|
||||||
accounts (:multiaccount/accounts db)
|
|
||||||
new-accounts (conj accounts account)]
|
|
||||||
(when account
|
|
||||||
(fx/merge cofx
|
|
||||||
{::json-rpc/call [{:method "accounts_saveAccounts"
|
|
||||||
:params [[account]]
|
|
||||||
:on-success #()}]
|
|
||||||
:db (-> db
|
|
||||||
(assoc :multiaccount/accounts new-accounts)
|
|
||||||
(dissoc :add-account))}
|
|
||||||
(when (= type :generate)
|
|
||||||
(multiaccounts.update/multiaccount-update
|
|
||||||
:latest-derived-path (inc latest-derived-path)
|
|
||||||
{}))
|
|
||||||
(wallet/update-balances nil)
|
|
||||||
(navigation/navigate-to-cofx :wallet nil)))))
|
|
||||||
|
|
||||||
(fx/defn start-adding-new-account
|
|
||||||
{:events [:wallet.accounts/start-adding-new-account]}
|
|
||||||
[{:keys [db] :as cofx} {:keys [type] :as add-account}]
|
|
||||||
(let [{:keys [keycard-pairing]} (:multiaccount db)
|
|
||||||
screen (case type
|
|
||||||
:generate (if keycard-pairing :add-new-account-pin
|
|
||||||
:add-new-account-password)
|
|
||||||
:watch :add-watch-account)]
|
|
||||||
(fx/merge cofx
|
|
||||||
{:db (cond-> (assoc db :add-account add-account)
|
|
||||||
keycard-pairing
|
|
||||||
(assoc-in [:hardwallet :pin :enter-step] :export-key))}
|
|
||||||
(navigation/navigate-to-cofx screen nil))))
|
|
||||||
|
|
||||||
(fx/defn enter-phrase-next-pressed
|
|
||||||
{:events [:wallet.accounts/enter-phrase-next-pressed]}
|
|
||||||
[{:keys [db] :as cofx}]
|
|
||||||
(fx/merge cofx
|
|
||||||
{:db (-> db
|
|
||||||
(dissoc :intro-wizard)
|
|
||||||
(assoc-in [:add-account :seed] (get-in db [:intro-wizard :passphrase])))}
|
|
||||||
(navigation/navigate-to-cofx :add-new-account-password nil)))
|
|
||||||
|
|
||||||
(fx/defn add-watch-account
|
|
||||||
{:events [:wallet.accounts/add-watch-account]}
|
|
||||||
[{:keys [db] :as cofx}]
|
|
||||||
(let [address (get-in db [:add-account :address])]
|
|
||||||
(fx/merge cofx
|
|
||||||
{:db (assoc-in db [:add-account :account]
|
|
||||||
{:name ""
|
|
||||||
:address (eip55/address->checksum (ethereum/normalized-hex address))
|
|
||||||
:type :watch
|
|
||||||
:color (rand-nth colors/account-colors)})}
|
|
||||||
(navigation/navigate-to-cofx :account-added nil))))
|
|
||||||
|
|
||||||
(fx/defn view-only-qr-scanner-result
|
(fx/defn view-only-qr-scanner-result
|
||||||
{:events [:wallet.add-new/qr-scanner-result]}
|
{:events [:wallet.add-new/qr-scanner-result]}
|
||||||
[{db :db :as cofx} data _]
|
[{db :db :as cofx} data _]
|
||||||
|
@ -184,3 +277,13 @@
|
||||||
{:utils/show-popup {:title (i18n/label :t/error)
|
{:utils/show-popup {:title (i18n/label :t/error)
|
||||||
:content (i18n/label :t/invalid-address-qr-code)}}))
|
:content (i18n/label :t/invalid-address-qr-code)}}))
|
||||||
(navigation/navigate-back))))
|
(navigation/navigate-back))))
|
||||||
|
|
||||||
|
(re-frame/reg-fx
|
||||||
|
:list.selection/open-share
|
||||||
|
(fn [obj]
|
||||||
|
(list-selection/open-share obj)))
|
||||||
|
|
||||||
|
(fx/defn wallet-accounts-share
|
||||||
|
{:events [:wallet.accounts/share]}
|
||||||
|
[_ address]
|
||||||
|
{:list.selection/open-share {:message (eip55/address->checksum address)}})
|
|
@ -443,7 +443,7 @@
|
||||||
"gas-price": "Gas price",
|
"gas-price": "Gas price",
|
||||||
"gas-used": "Gas used",
|
"gas-used": "Gas used",
|
||||||
"generate-a-key": "Generate keys",
|
"generate-a-key": "Generate keys",
|
||||||
"generate-a-new-account": "Generate keys",
|
"generate-a-new-account": "Generate an account",
|
||||||
"generate-a-new-key": "Generate a new key",
|
"generate-a-new-key": "Generate a new key",
|
||||||
"generate-account": "Generate keys",
|
"generate-account": "Generate keys",
|
||||||
"generate-new-key": "Generate keys",
|
"generate-new-key": "Generate keys",
|
||||||
|
@ -1079,6 +1079,7 @@
|
||||||
"select-account-dapp": "Select the account you wish to use with Dapps",
|
"select-account-dapp": "Select the account you wish to use with Dapps",
|
||||||
"apply": "Apply",
|
"apply": "Apply",
|
||||||
"on-status-tree": "On Status tree",
|
"on-status-tree": "On Status tree",
|
||||||
|
"off-status-tree": "Off Status tree",
|
||||||
"derivation-path": "Derivation path",
|
"derivation-path": "Derivation path",
|
||||||
"storage": "Storage",
|
"storage": "Storage",
|
||||||
"keycard-free-pairing-slots": "Keycard has {{n}} free pairing slots",
|
"keycard-free-pairing-slots": "Keycard has {{n}} free pairing slots",
|
||||||
|
@ -1089,5 +1090,11 @@
|
||||||
"mail-should-be-configured": "Mail client should be configured",
|
"mail-should-be-configured": "Mail client should be configured",
|
||||||
"check-on-etherscan": "Check on etherscan",
|
"check-on-etherscan": "Check on etherscan",
|
||||||
"transactions-load-more": "Load more",
|
"transactions-load-more": "Load more",
|
||||||
|
"private-key": "Private key",
|
||||||
|
"generate-an-account": "Generate an account",
|
||||||
|
"add-watch-account": "Add a watch-only account",
|
||||||
|
"add-seed-account": "Add account with a seed phrase",
|
||||||
|
"account-exists-title": "Account already exists",
|
||||||
|
"add-private-key-account": "Add account from private key",
|
||||||
"user-not-found": "User not found"
|
"user-not-found": "User not found"
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue