diff --git a/src/quo/components/wallet/keypair/component_spec.cljs b/src/quo/components/wallet/keypair/component_spec.cljs index 95e41e71cb..ae218460c5 100644 --- a/src/quo/components/wallet/keypair/component_spec.cljs +++ b/src/quo/components/wallet/keypair/component_spec.cljs @@ -55,7 +55,7 @@ :action :selector :details other-details}] theme) - (h/is-truthy (h/get-by-label-text :radio-on))) + (h/is-truthy (h/get-by-label-text :radio-off))) (h/test "Options action renders" (h/render-with-theme-provider [keypair/view diff --git a/src/quo/components/wallet/keypair/style.cljs b/src/quo/components/wallet/keypair/style.cljs index 69c22930e4..dd506c8098 100644 --- a/src/quo/components/wallet/keypair/style.cljs +++ b/src/quo/components/wallet/keypair/style.cljs @@ -1,6 +1,7 @@ (ns quo.components.wallet.keypair.style (:require - [quo.foundations.colors :as colors])) + [quo.foundations.colors :as colors] + [react-native.platform :as platform])) (defn container [{:keys [blur? customization-color theme selected?]}] @@ -34,3 +35,8 @@ {:color (if blur? colors/white-opa-40 (colors/theme-colors colors/neutral-50 colors/neutral-40 theme))}) + +(defn dot + [blur? theme] + (merge (subtitle blur? theme) + {:bottom (if platform/ios? 2 -2)})) diff --git a/src/quo/components/wallet/keypair/view.cljs b/src/quo/components/wallet/keypair/view.cljs index 2658f63371..50bfff8170 100644 --- a/src/quo/components/wallet/keypair/view.cljs +++ b/src/quo/components/wallet/keypair/view.cljs @@ -11,7 +11,6 @@ [quo.foundations.colors :as colors] [quo.theme :as quo.theme] [react-native.core :as rn] - [react-native.platform :as platform] [reagent.core :as reagent] [utils.i18n :as i18n])) @@ -60,7 +59,7 @@ :accessibility-label :options-button}]])])) (defn details-view - [{:keys [details stored blur? theme]}] + [{:keys [details stored type blur? theme]}] (let [{:keys [address]} details] [rn/view {:style {:flex-direction :row @@ -70,10 +69,11 @@ {:size :paragraph-2 :style (style/subtitle blur? theme)} address] - [text/text - {:size :paragraph-2 - :style (merge (style/subtitle blur? theme) {:bottom (if platform/ios? 2 -2)})} - " ∙ "] + (when (= type :default-keypair) + [text/text + {:size :paragraph-2 + :style (style/dot blur? theme)} + " ∙ "]) [text/text {:size :paragraph-2 :style (style/subtitle blur? theme)} @@ -87,8 +87,8 @@ (colors/theme-colors colors/neutral-50 colors/neutral-40 theme))}]])])) (defn- view-internal - [] - (let [selected? (reagent/atom true)] + [{:keys [default-selected?]}] + (let [selected? (reagent/atom default-selected?)] (fn [{:keys [accounts action container-style] :as props}] [rn/pressable {:style (merge (style/container (merge props {:selected? @selected?})) container-style) diff --git a/src/status_im/contexts/wallet/create_account/new_keypair/backup_recovery_phrase/view.cljs b/src/status_im/contexts/wallet/create_account/new_keypair/backup_recovery_phrase/view.cljs index 5db032f9fc..ad5d8ec230 100644 --- a/src/status_im/contexts/wallet/create_account/new_keypair/backup_recovery_phrase/view.cljs +++ b/src/status_im/contexts/wallet/create_account/new_keypair/backup_recovery_phrase/view.cljs @@ -49,7 +49,7 @@ secret-phrase (reagent/atom []) random-phrase (reagent/atom [])] (fn [] - (rn/use-effect + (rn/use-mount (fn [] (native-module/get-random-mnemonic #(reset! secret-phrase (string/split % #"\s"))) (native-module/get-random-mnemonic #(reset! random-phrase (string/split % #"\s"))))) diff --git a/src/status_im/contexts/wallet/create_account/select_keypair/view.cljs b/src/status_im/contexts/wallet/create_account/select_keypair/view.cljs index 6b19284866..c2fbe6234c 100644 --- a/src/status_im/contexts/wallet/create_account/select_keypair/view.cljs +++ b/src/status_im/contexts/wallet/create_account/select_keypair/view.cljs @@ -1,14 +1,16 @@ (ns status-im.contexts.wallet.create-account.select-keypair.view (:require + [clojure.string :as string] [quo.core :as quo] [react-native.core :as rn] + [status-im.constants :as constants] [status-im.contexts.profile.utils :as profile.utils] [status-im.contexts.wallet.create-account.select-keypair.style :as style] [utils.address :as utils] [utils.i18n :as i18n] [utils.re-frame :as rf])) -(defn keypair-options +(defn- keypair-options [] [quo/action-drawer [[{:icon :i/add @@ -26,25 +28,51 @@ :accessibility-label :import-private-key :label (i18n/label :t/import-private-key)}]]]) -(def accounts - [{:account-props {:customization-color :turquoise - :size 32 - :emoji "\uD83C\uDFB2" - :type :default - :name "Trip to Vegas" - :address "0x0ah...71a"} - :networks [{:network-name :ethereum :short-name "eth"} - {:network-name :optimism :short-name "opt"}] - :state :default - :action :none}]) +(defn- parse-accounts + [given-accounts] + (->> given-accounts + (filter (fn [{:keys [path]}] + (not (string/starts-with? path constants/path-eip1581)))) + (map (fn [{:keys [customization-color emoji name address]}] + {:account-props {:customization-color customization-color + :size 32 + :emoji emoji + :type :default + :name name + :address address} + :networks [{:network-name :ethereum :short-name "eth"} + {:network-name :optimism :short-name "opt"} + {:network-name :arbitrum :short-name "arb1"}] + :state :default + :action :none})))) +(defn- keypair + [item index _ {:keys [profile-picture compressed-key]}] + (let [main-account (first (:accounts item)) + color (:customization-color main-account) + accounts (parse-accounts (:accounts item))] + [quo/keypair + {:customization-color color + :profile-picture (when (zero? index) profile-picture) + :status-indicator false + :type (if (zero? index) :default-keypair :other) + :stored :on-device + :on-options-press #(js/alert "Options pressed") + :action :selector + :blur? false + :details {:full-name (:name item) + :address (when (zero? index) + (utils/get-shortened-compressed-key compressed-key))} + :accounts accounts + :default-selected? (zero? index) + :container-style {:margin-horizontal 20 + :margin-vertical 8}}])) (defn view [] - (let [{:keys [public-key compressed-key - customization-color]} (rf/sub [:profile/profile]) - [display-name _] (rf/sub [:contacts/contact-two-names-by-identity public-key]) - profile-with-image (rf/sub [:profile/profile-with-image]) - profile-picture (profile.utils/photo profile-with-image)] + (let [{:keys [compressed-key customization-color]} (rf/sub [:profile/profile]) + profile-with-image (rf/sub [:profile/profile-with-image]) + keypairs (rf/sub [:wallet/keypairs]) + profile-picture (profile.utils/photo profile-with-image)] [rn/view {:style {:flex 1}} [quo/page-nav {:icon-name :i/close @@ -60,20 +88,12 @@ [:show-bottom-sheet {:content keypair-options}])} :description :text :description-text (i18n/label :t/keypairs-description)}] - [quo/keypair - {:customization-color customization-color - :profile-picture profile-picture - :status-indicator false - :type :default-keypair - :stored :on-device - :on-options-press #(js/alert "Options pressed") - :action :selector - :blur? false - :details {:full-name display-name - :address (utils/get-shortened-compressed-key compressed-key)} - :accounts accounts - :container-style {:margin-horizontal 20 - :margin-vertical 8}}] + [rn/flat-list + {:data keypairs + :render-fn keypair + :render-data {:profile-picture profile-picture + :compressed-key compressed-key} + :content-container-style {:padding-bottom 60}}] [quo/bottom-actions {:actions :one-action :button-one-label (i18n/label :t/confirm-account-origin) diff --git a/src/status_im/contexts/wallet/create_account/utils.cljs b/src/status_im/contexts/wallet/create_account/utils.cljs new file mode 100644 index 0000000000..7af9ddb1e8 --- /dev/null +++ b/src/status_im/contexts/wallet/create_account/utils.cljs @@ -0,0 +1,19 @@ +(ns status-im.contexts.wallet.create-account.utils) + +(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)}])) diff --git a/src/status_im/contexts/wallet/create_account/view.cljs b/src/status_im/contexts/wallet/create_account/view.cljs index 1011941c6f..9ca83078b8 100644 --- a/src/status_im/contexts/wallet/create_account/view.cljs +++ b/src/status_im/contexts/wallet/create_account/view.cljs @@ -13,13 +13,14 @@ [status-im.contexts.wallet.common.sheets.account-origin.view :as account-origin] [status-im.contexts.wallet.common.utils :as utils] [status-im.contexts.wallet.create-account.style :as style] - [status-im.feature-flags :as ff] + [status-im.contexts.wallet.create-account.utils :as create-account.utils] [utils.i18n :as i18n] [utils.re-frame :as rf] [utils.responsiveness :refer [iphone-11-Pro-20-pixel-from-width]] [utils.security.core :as security] [utils.string])) + (defn- get-keypair-data [primary-name derivation-path account-color {:keys [keypair-name]}] [{:title (or keypair-name (i18n/label :t/keypair-title {:name primary-name})) @@ -30,9 +31,8 @@ :size :xxs :customization-color account-color}) :action (when-not keypair-name :button) - :action-props {:on-press #(ff/alert ::ff/wallet.edit-default-keypair - (fn [] - (rf/dispatch [:navigate-to :wallet-select-keypair]))) + :action-props {:on-press (fn [] + (rf/dispatch [:navigate-to :wallet-select-keypair])) :button-text (i18n/label :t/edit) :alignment :flex-start} :description :text @@ -50,22 +50,23 @@ (defn- f-view [] - (let [top (safe-area/get-top) - bottom (safe-area/get-bottom) - account-color (reagent/atom (rand-nth colors/account-colors)) - emoji (reagent/atom (emoji-picker.utils/random-emoji)) - number-of-accounts (count (rf/sub [:wallet/accounts-without-watched-accounts])) - account-name (reagent/atom "") - placeholder (i18n/label :t/default-account-placeholder - {:number (inc number-of-accounts)}) - derivation-path (reagent/atom (utils/get-derivation-path number-of-accounts)) - {:keys [public-key]} (rf/sub [:profile/profile]) - on-change-text #(reset! account-name %) - primary-name (first (rf/sub [:contacts/contact-two-names-by-identity public-key])) - {window-width :width} (rn/get-window)] + (let [top (safe-area/get-top) + bottom (safe-area/get-bottom) + account-color (reagent/atom (rand-nth colors/account-colors)) + emoji (reagent/atom (emoji-picker.utils/random-emoji)) + number-of-accounts (count (rf/sub [:wallet/accounts-without-watched-accounts])) + account-name (reagent/atom "") + placeholder (i18n/label :t/default-account-placeholder + {:number (inc number-of-accounts)}) + derivation-path (reagent/atom (utils/get-derivation-path number-of-accounts)) + {:keys [public-key address]} (rf/sub [:profile/profile]) + on-change-text #(reset! account-name %) + primary-name (first (rf/sub [:contacts/contact-two-names-by-identity + public-key])) + {window-width :width} (rn/get-window)] (fn [{:keys [theme]}] (let [{:keys [new-keypair]} (rf/sub [:wallet/create-account])] - (rn/use-effect (fn [] #(rf/dispatch [:wallet/clear-new-keypair]))) + (rn/use-unmount #(rf/dispatch [:wallet/clear-new-keypair])) [rn/view {:style {:flex 1}} [quo/page-nav {:type :no-title @@ -127,7 +128,18 @@ :customization-color @account-color :on-auth-success (fn [entered-password] (if new-keypair - (js/alert "Feature under development") + (rf/dispatch + [:wallet/add-keypair-and-create-account + {:sha3-pwd (security/safe-unmask-data + entered-password) + :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})}]) (rf/dispatch [:wallet/derive-address-and-add-account {:sha3-pwd (security/safe-unmask-data entered-password) diff --git a/src/status_im/contexts/wallet/data_store.cljs b/src/status_im/contexts/wallet/data_store.cljs index 7782146076..8421e680ca 100644 --- a/src/status_im/contexts/wallet/data_store.cljs +++ b/src/status_im/contexts/wallet/data_store.cljs @@ -23,8 +23,8 @@ (assoc account :watch-only? (= (:type account) :watch))) (defn- sanitize-emoji - "As Desktop uses Twemoji, the emoji received can be an img tag - with raw emoji in alt attribute. This function help us to extract + "As Desktop uses Twemoji, the emoji received can be an img tag + with raw emoji in alt attribute. This function help us to extract the emoji from it as mobile doesn't support HTML rendering and Twemoji" [emoji] (if (string/starts-with? emoji "kebab-case-keyword renamed-data))) diff --git a/src/status_im/contexts/wallet/events.cljs b/src/status_im/contexts/wallet/events.cljs index 29caad5030..1d3e8ad7e0 100644 --- a/src/status_im/contexts/wallet/events.cljs +++ b/src/status_im/contexts/wallet/events.cljs @@ -202,6 +202,35 @@ (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) + +(defn get-keypairs + [_] + {:fx [[:json-rpc/call + [{:method "accounts_getKeypairs" + :params [] + :on-success [:wallet/get-keypairs-success] + :on-error #(log/info "failed to get keypairs " %)}]]]}) + +(rf/reg-event-fx :wallet/get-keypairs get-keypairs) + +(defn get-keypairs-success + [{:keys [db]} [keypairs]] + {:db (assoc-in db [:wallet :keypairs] (data-store/parse-keypairs keypairs))}) + +(rf/reg-event-fx :wallet/get-keypairs-success get-keypairs-success) + (rf/reg-event-fx :wallet/bridge-select-token (fn [{:keys [db]} [{:keys [token stack-id]}]] (let [to-address (get-in db [:wallet :current-viewing-account-address])] @@ -371,7 +400,8 @@ (fn [] {:fx [[:dispatch [:wallet/start-wallet]] [:dispatch [:wallet/get-ethereum-chains]] - [:dispatch [:wallet/get-accounts]]]})) + [:dispatch [:wallet/get-accounts]] + [:dispatch [:wallet/get-keypairs]]]})) (rf/reg-event-fx :wallet/share-account (fn [_ [{:keys [content title]}]] diff --git a/src/status_im/contexts/wallet/events_test.cljs b/src/status_im/contexts/wallet/events_test.cljs index 3cec6a9845..96a6afbd11 100644 --- a/src/status_im/contexts/wallet/events_test.cljs +++ b/src/status_im/contexts/wallet/events_test.cljs @@ -55,7 +55,6 @@ effects (events/clear-new-keypair {:db db})] (is (match? (:db effects) expected-db)))) - (deftest store-collectibles (testing "(displayable-collectible?) helper function" (let [expected-results [[true diff --git a/src/status_im/feature_flags.cljs b/src/status_im/feature_flags.cljs index d503ee8c71..0d0ddb7ed8 100644 --- a/src/status_im/feature_flags.cljs +++ b/src/status_im/feature_flags.cljs @@ -10,7 +10,7 @@ (defonce ^:private feature-flags-config (reagent/atom - {::wallet.edit-default-keypair (enabled-in-env? :FLAG_EDIT_DEFAULT_KEYPAIR_ENABLED) + {::wallet.edit-default-keypair true ::wallet.bridge-token (enabled-in-env? :FLAG_BRIDGE_TOKEN_ENABLED) ::wallet.remove-account (enabled-in-env? :FLAG_REMOVE_ACCOUNT_ENABLED) ::wallet.network-filter (enabled-in-env? :FLAG_NETWORK_FILTER_ENABLED) diff --git a/src/status_im/subs/wallet/wallet.cljs b/src/status_im/subs/wallet/wallet.cljs index ce9b5b705c..3f31c97b47 100644 --- a/src/status_im/subs/wallet/wallet.cljs +++ b/src/status_im/subs/wallet/wallet.cljs @@ -93,6 +93,11 @@ :<- [:wallet/ui] :-> :watch-address-activity-state) +(rf/reg-sub + :wallet/keypairs + :<- [:wallet] + :-> :keypairs) + (rf/reg-sub :wallet/accounts :<- [:wallet] diff --git a/src/status_im/subs/wallet/wallet_test.cljs b/src/status_im/subs/wallet/wallet_test.cljs index a301bcc8fb..0917c40f1a 100644 --- a/src/status_im/subs/wallet/wallet_test.cljs +++ b/src/status_im/subs/wallet/wallet_test.cljs @@ -497,3 +497,15 @@ (get "0x3") (assoc :network-preferences-names #{}))] (rf/sub [sub-name]))))) + +(def keypairs + [{:key-uid "abc"}]) + +(h/deftest-sub :wallet/keypairs + [sub-name] + (testing "returns all keypairs" + (swap! rf-db/app-db + #(assoc-in % [:wallet :keypairs] keypairs)) + (is + (= keypairs + (rf/sub [sub-name])))))