Wallet: finalize kp (#18991)

Wallet: finalize kp
This commit is contained in:
Omar Basem 2024-03-01 08:09:36 +04:00 committed by GitHub
parent ac78dea8ef
commit abd2b43ce6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 189 additions and 66 deletions

View File

@ -55,7 +55,7 @@
:action :selector :action :selector
:details other-details}] :details other-details}]
theme) 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/test "Options action renders"
(h/render-with-theme-provider [keypair/view (h/render-with-theme-provider [keypair/view

View File

@ -1,6 +1,7 @@
(ns quo.components.wallet.keypair.style (ns quo.components.wallet.keypair.style
(:require (:require
[quo.foundations.colors :as colors])) [quo.foundations.colors :as colors]
[react-native.platform :as platform]))
(defn container (defn container
[{:keys [blur? customization-color theme selected?]}] [{:keys [blur? customization-color theme selected?]}]
@ -34,3 +35,8 @@
{:color (if blur? {:color (if blur?
colors/white-opa-40 colors/white-opa-40
(colors/theme-colors colors/neutral-50 colors/neutral-40 theme))}) (colors/theme-colors colors/neutral-50 colors/neutral-40 theme))})
(defn dot
[blur? theme]
(merge (subtitle blur? theme)
{:bottom (if platform/ios? 2 -2)}))

View File

@ -11,7 +11,6 @@
[quo.foundations.colors :as colors] [quo.foundations.colors :as colors]
[quo.theme :as quo.theme] [quo.theme :as quo.theme]
[react-native.core :as rn] [react-native.core :as rn]
[react-native.platform :as platform]
[reagent.core :as reagent] [reagent.core :as reagent]
[utils.i18n :as i18n])) [utils.i18n :as i18n]))
@ -60,7 +59,7 @@
:accessibility-label :options-button}]])])) :accessibility-label :options-button}]])]))
(defn details-view (defn details-view
[{:keys [details stored blur? theme]}] [{:keys [details stored type blur? theme]}]
(let [{:keys [address]} details] (let [{:keys [address]} details]
[rn/view [rn/view
{:style {:flex-direction :row {:style {:flex-direction :row
@ -70,10 +69,11 @@
{:size :paragraph-2 {:size :paragraph-2
:style (style/subtitle blur? theme)} :style (style/subtitle blur? theme)}
address] address]
[text/text (when (= type :default-keypair)
{:size :paragraph-2 [text/text
:style (merge (style/subtitle blur? theme) {:bottom (if platform/ios? 2 -2)})} {:size :paragraph-2
" ∙ "] :style (style/dot blur? theme)}
" ∙ "])
[text/text [text/text
{:size :paragraph-2 {:size :paragraph-2
:style (style/subtitle blur? theme)} :style (style/subtitle blur? theme)}
@ -87,8 +87,8 @@
(colors/theme-colors colors/neutral-50 colors/neutral-40 theme))}]])])) (colors/theme-colors colors/neutral-50 colors/neutral-40 theme))}]])]))
(defn- view-internal (defn- view-internal
[] [{:keys [default-selected?]}]
(let [selected? (reagent/atom true)] (let [selected? (reagent/atom default-selected?)]
(fn [{:keys [accounts action container-style] :as props}] (fn [{:keys [accounts action container-style] :as props}]
[rn/pressable [rn/pressable
{:style (merge (style/container (merge props {:selected? @selected?})) container-style) {:style (merge (style/container (merge props {:selected? @selected?})) container-style)

View File

@ -49,7 +49,7 @@
secret-phrase (reagent/atom []) secret-phrase (reagent/atom [])
random-phrase (reagent/atom [])] random-phrase (reagent/atom [])]
(fn [] (fn []
(rn/use-effect (rn/use-mount
(fn [] (fn []
(native-module/get-random-mnemonic #(reset! secret-phrase (string/split % #"\s"))) (native-module/get-random-mnemonic #(reset! secret-phrase (string/split % #"\s")))
(native-module/get-random-mnemonic #(reset! random-phrase (string/split % #"\s"))))) (native-module/get-random-mnemonic #(reset! random-phrase (string/split % #"\s")))))

View File

@ -1,14 +1,16 @@
(ns status-im.contexts.wallet.create-account.select-keypair.view (ns status-im.contexts.wallet.create-account.select-keypair.view
(:require (:require
[clojure.string :as string]
[quo.core :as quo] [quo.core :as quo]
[react-native.core :as rn] [react-native.core :as rn]
[status-im.constants :as constants]
[status-im.contexts.profile.utils :as profile.utils] [status-im.contexts.profile.utils :as profile.utils]
[status-im.contexts.wallet.create-account.select-keypair.style :as style] [status-im.contexts.wallet.create-account.select-keypair.style :as style]
[utils.address :as utils] [utils.address :as utils]
[utils.i18n :as i18n] [utils.i18n :as i18n]
[utils.re-frame :as rf])) [utils.re-frame :as rf]))
(defn keypair-options (defn- keypair-options
[] []
[quo/action-drawer [quo/action-drawer
[[{:icon :i/add [[{:icon :i/add
@ -26,25 +28,51 @@
:accessibility-label :import-private-key :accessibility-label :import-private-key
:label (i18n/label :t/import-private-key)}]]]) :label (i18n/label :t/import-private-key)}]]])
(def accounts (defn- parse-accounts
[{:account-props {:customization-color :turquoise [given-accounts]
:size 32 (->> given-accounts
:emoji "\uD83C\uDFB2" (filter (fn [{:keys [path]}]
:type :default (not (string/starts-with? path constants/path-eip1581))))
:name "Trip to Vegas" (map (fn [{:keys [customization-color emoji name address]}]
:address "0x0ah...71a"} {:account-props {:customization-color customization-color
:networks [{:network-name :ethereum :short-name "eth"} :size 32
{:network-name :optimism :short-name "opt"}] :emoji emoji
:state :default :type :default
:action :none}]) :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 (defn view
[] []
(let [{:keys [public-key compressed-key (let [{:keys [compressed-key customization-color]} (rf/sub [:profile/profile])
customization-color]} (rf/sub [:profile/profile]) profile-with-image (rf/sub [:profile/profile-with-image])
[display-name _] (rf/sub [:contacts/contact-two-names-by-identity public-key]) keypairs (rf/sub [:wallet/keypairs])
profile-with-image (rf/sub [:profile/profile-with-image]) profile-picture (profile.utils/photo profile-with-image)]
profile-picture (profile.utils/photo profile-with-image)]
[rn/view {:style {:flex 1}} [rn/view {:style {:flex 1}}
[quo/page-nav [quo/page-nav
{:icon-name :i/close {:icon-name :i/close
@ -60,20 +88,12 @@
[:show-bottom-sheet {:content keypair-options}])} [:show-bottom-sheet {:content keypair-options}])}
:description :text :description :text
:description-text (i18n/label :t/keypairs-description)}] :description-text (i18n/label :t/keypairs-description)}]
[quo/keypair [rn/flat-list
{:customization-color customization-color {:data keypairs
:profile-picture profile-picture :render-fn keypair
:status-indicator false :render-data {:profile-picture profile-picture
:type :default-keypair :compressed-key compressed-key}
:stored :on-device :content-container-style {:padding-bottom 60}}]
: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}}]
[quo/bottom-actions [quo/bottom-actions
{:actions :one-action {:actions :one-action
:button-one-label (i18n/label :t/confirm-account-origin) :button-one-label (i18n/label :t/confirm-account-origin)

View File

@ -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)}]))

View File

@ -13,13 +13,14 @@
[status-im.contexts.wallet.common.sheets.account-origin.view :as account-origin] [status-im.contexts.wallet.common.sheets.account-origin.view :as account-origin]
[status-im.contexts.wallet.common.utils :as utils] [status-im.contexts.wallet.common.utils :as utils]
[status-im.contexts.wallet.create-account.style :as style] [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.i18n :as i18n]
[utils.re-frame :as rf] [utils.re-frame :as rf]
[utils.responsiveness :refer [iphone-11-Pro-20-pixel-from-width]] [utils.responsiveness :refer [iphone-11-Pro-20-pixel-from-width]]
[utils.security.core :as security] [utils.security.core :as security]
[utils.string])) [utils.string]))
(defn- get-keypair-data (defn- get-keypair-data
[primary-name derivation-path account-color {:keys [keypair-name]}] [primary-name derivation-path account-color {:keys [keypair-name]}]
[{:title (or keypair-name (i18n/label :t/keypair-title {:name primary-name})) [{:title (or keypair-name (i18n/label :t/keypair-title {:name primary-name}))
@ -30,9 +31,8 @@
:size :xxs :size :xxs
:customization-color account-color}) :customization-color account-color})
:action (when-not keypair-name :button) :action (when-not keypair-name :button)
:action-props {:on-press #(ff/alert ::ff/wallet.edit-default-keypair :action-props {:on-press (fn []
(fn [] (rf/dispatch [:navigate-to :wallet-select-keypair]))
(rf/dispatch [:navigate-to :wallet-select-keypair])))
:button-text (i18n/label :t/edit) :button-text (i18n/label :t/edit)
:alignment :flex-start} :alignment :flex-start}
:description :text :description :text
@ -50,22 +50,23 @@
(defn- f-view (defn- f-view
[] []
(let [top (safe-area/get-top) (let [top (safe-area/get-top)
bottom (safe-area/get-bottom) bottom (safe-area/get-bottom)
account-color (reagent/atom (rand-nth colors/account-colors)) account-color (reagent/atom (rand-nth colors/account-colors))
emoji (reagent/atom (emoji-picker.utils/random-emoji)) emoji (reagent/atom (emoji-picker.utils/random-emoji))
number-of-accounts (count (rf/sub [:wallet/accounts-without-watched-accounts])) number-of-accounts (count (rf/sub [:wallet/accounts-without-watched-accounts]))
account-name (reagent/atom "") account-name (reagent/atom "")
placeholder (i18n/label :t/default-account-placeholder placeholder (i18n/label :t/default-account-placeholder
{:number (inc number-of-accounts)}) {:number (inc number-of-accounts)})
derivation-path (reagent/atom (utils/get-derivation-path number-of-accounts)) derivation-path (reagent/atom (utils/get-derivation-path number-of-accounts))
{:keys [public-key]} (rf/sub [:profile/profile]) {:keys [public-key address]} (rf/sub [:profile/profile])
on-change-text #(reset! account-name %) on-change-text #(reset! account-name %)
primary-name (first (rf/sub [:contacts/contact-two-names-by-identity public-key])) primary-name (first (rf/sub [:contacts/contact-two-names-by-identity
{window-width :width} (rn/get-window)] public-key]))
{window-width :width} (rn/get-window)]
(fn [{:keys [theme]}] (fn [{:keys [theme]}]
(let [{:keys [new-keypair]} (rf/sub [:wallet/create-account])] (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}} [rn/view {:style {:flex 1}}
[quo/page-nav [quo/page-nav
{:type :no-title {:type :no-title
@ -127,7 +128,18 @@
:customization-color @account-color :customization-color @account-color
:on-auth-success (fn [entered-password] :on-auth-success (fn [entered-password]
(if new-keypair (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 (rf/dispatch [:wallet/derive-address-and-add-account
{:sha3-pwd (security/safe-unmask-data {:sha3-pwd (security/safe-unmask-data
entered-password) entered-password)

View File

@ -23,8 +23,8 @@
(assoc account :watch-only? (= (:type account) :watch))) (assoc account :watch-only? (= (:type account) :watch)))
(defn- sanitize-emoji (defn- sanitize-emoji
"As Desktop uses Twemoji, the emoji received can be an img tag "As Desktop uses Twemoji, the emoji received can be an img tag
with raw emoji in alt attribute. This function help us to extract 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" the emoji from it as mobile doesn't support HTML rendering and Twemoji"
[emoji] [emoji]
(if (string/starts-with? emoji "<img") (if (string/starts-with? emoji "<img")
@ -104,3 +104,23 @@
:blockExplorerUrl :block-explorer-url :blockExplorerUrl :block-explorer-url
:nativeCurrencySymbol :native-currency-symbol :nativeCurrencySymbol :native-currency-symbol
:nativeCurrencyName :native-currency-symbol}))) :nativeCurrencyName :native-currency-symbol})))
(defn rename-color-id-in-data
[data]
(map (fn [item]
(update item
:accounts
(fn [accounts]
(map (fn [account]
(let [renamed-account (set/rename-keys account
{:colorId :customization-color})]
(if (contains? account :colorId)
renamed-account
(assoc renamed-account :customization-color :blue))))
accounts))))
data))
(defn parse-keypairs
[keypairs]
(let [renamed-data (rename-color-id-in-data keypairs)]
(cske/transform-keys csk/->kebab-case-keyword renamed-data)))

View File

@ -202,6 +202,35 @@
(first derived-address-details)]))] (first derived-address-details)]))]
{:fx [[:dispatch [:wallet/create-derived-addresses account-details on-success]]]}))) {: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 (rf/reg-event-fx :wallet/bridge-select-token
(fn [{:keys [db]} [{:keys [token stack-id]}]] (fn [{:keys [db]} [{:keys [token stack-id]}]]
(let [to-address (get-in db [:wallet :current-viewing-account-address])] (let [to-address (get-in db [:wallet :current-viewing-account-address])]
@ -371,7 +400,8 @@
(fn [] (fn []
{:fx [[:dispatch [:wallet/start-wallet]] {:fx [[:dispatch [:wallet/start-wallet]]
[:dispatch [:wallet/get-ethereum-chains]] [:dispatch [:wallet/get-ethereum-chains]]
[:dispatch [:wallet/get-accounts]]]})) [:dispatch [:wallet/get-accounts]]
[:dispatch [:wallet/get-keypairs]]]}))
(rf/reg-event-fx :wallet/share-account (rf/reg-event-fx :wallet/share-account
(fn [_ [{:keys [content title]}]] (fn [_ [{:keys [content title]}]]

View File

@ -55,7 +55,6 @@
effects (events/clear-new-keypair {:db db})] effects (events/clear-new-keypair {:db db})]
(is (match? (:db effects) expected-db)))) (is (match? (:db effects) expected-db))))
(deftest store-collectibles (deftest store-collectibles
(testing "(displayable-collectible?) helper function" (testing "(displayable-collectible?) helper function"
(let [expected-results [[true (let [expected-results [[true

View File

@ -10,7 +10,7 @@
(defonce ^:private feature-flags-config (defonce ^:private feature-flags-config
(reagent/atom (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.bridge-token (enabled-in-env? :FLAG_BRIDGE_TOKEN_ENABLED)
::wallet.remove-account (enabled-in-env? :FLAG_REMOVE_ACCOUNT_ENABLED) ::wallet.remove-account (enabled-in-env? :FLAG_REMOVE_ACCOUNT_ENABLED)
::wallet.network-filter (enabled-in-env? :FLAG_NETWORK_FILTER_ENABLED) ::wallet.network-filter (enabled-in-env? :FLAG_NETWORK_FILTER_ENABLED)

View File

@ -93,6 +93,11 @@
:<- [:wallet/ui] :<- [:wallet/ui]
:-> :watch-address-activity-state) :-> :watch-address-activity-state)
(rf/reg-sub
:wallet/keypairs
:<- [:wallet]
:-> :keypairs)
(rf/reg-sub (rf/reg-sub
:wallet/accounts :wallet/accounts
:<- [:wallet] :<- [:wallet]

View File

@ -497,3 +497,15 @@
(get "0x3") (get "0x3")
(assoc :network-preferences-names #{}))] (assoc :network-preferences-names #{}))]
(rf/sub [sub-name]))))) (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])))))