From a3e713bbf06ddd39724a7d4dfc4399634a0e9eed Mon Sep 17 00:00:00 2001 From: Mohamed Javid <19339952+smohamedjavid@users.noreply.github.com> Date: Fri, 7 Jun 2024 19:47:06 +0530 Subject: [PATCH] feat(wallet): Add a new saved address with ENS (#20384) This commit adds a feature to add new saved addresses with ENS Signed-off-by: Mohamed Javid <19339952+smohamedjavid@users.noreply.github.com> --- .../add_address_to_save/view.cljs | 96 ++++++++++++------- .../wallet/saved_addresses/events_test.cljs | 6 +- .../saved_addresses/save_address/view.cljs | 49 ++++++---- .../sheets/address_options/view.cljs | 10 +- .../settings/wallet/saved_addresses/view.cljs | 46 +++++---- .../contexts/wallet/common/validation.cljs | 2 +- src/status_im/contexts/wallet/data_store.cljs | 2 +- src/status_im/contexts/wallet/events.cljs | 10 ++ .../subs/wallet/saved_addresses_test.cljs | 12 +-- 9 files changed, 139 insertions(+), 94 deletions(-) diff --git a/src/status_im/contexts/settings/wallet/saved_addresses/add_address_to_save/view.cljs b/src/status_im/contexts/settings/wallet/saved_addresses/add_address_to_save/view.cljs index 5fa228cffd..936de8a238 100644 --- a/src/status_im/contexts/settings/wallet/saved_addresses/add_address_to_save/view.cljs +++ b/src/status_im/contexts/settings/wallet/saved_addresses/add_address_to_save/view.cljs @@ -8,6 +8,7 @@ [status-im.common.floating-button-page.view :as floating-button-page] [status-im.contexts.settings.wallet.saved-addresses.add-address-to-save.style :as style] [status-im.contexts.wallet.common.validation :as validation] + [utils.debounce :as debounce] [utils.i18n :as i18n] [utils.re-frame :as rf])) @@ -18,7 +19,7 @@ (defn- validate-input [account-addresses saved-addresses user-input] (cond - (or (nil? user-input) (= user-input "")) + (string/blank? user-input) nil (contains? saved-addresses user-input) @@ -89,7 +90,7 @@ (defn- existing-saved-address [{:keys [address]}] - (let [{:keys [name customization-color chain-short-names ens has-ens?]} + (let [{:keys [name customization-color chain-short-names ens ens?]} (rf/sub [:wallet/saved-address-by-address address])] [rn/view {:style style/existing-saved-address-container} @@ -103,43 +104,65 @@ :active-state? true :user-props {:name name :address (str chain-short-names address) - :ens (when has-ens? ens) + :ens (when ens? ens) :customization-color customization-color :blur? true} :container-style style/saved-address-item}]])) (defn view [] - (let [profile-color (rf/sub [:profile/customization-color]) - accounts-addresses (rf/sub [:wallet/addresses]) - saved-addresses-addresses (rf/sub [:wallet/saved-addresses-addresses]) - [input-value set-input-value] (rn/use-state nil) - [error set-error] (rn/use-state nil) - error? (some? error) - validate #(validate-input accounts-addresses - saved-addresses-addresses - %) - clear-input (rn/use-callback - (fn [] - (set-input-value nil) - (set-error nil))) - on-change-text (rn/use-callback - (fn [new-value] - (let [lowercase-value (string/lower-case new-value)] - (set-error (validate lowercase-value)) - (set-input-value lowercase-value)))) - paste-into-input (rn/use-callback #(clipboard/get-string - (fn [clipboard-text] - (on-change-text clipboard-text)))) - on-press-continue (rn/use-callback - (fn [] - (rf/dispatch [:wallet/set-address-to-save - {:address input-value}]) - (rf/dispatch - [:navigate-to-within-stack - [:screen/settings.save-address - :screen/settings.add-address-to-save]])) - [input-value])] + (let [profile-color (rf/sub [:profile/customization-color]) + accounts-addresses (rf/sub [:wallet/addresses]) + saved-addresses-addresses (rf/sub [:wallet/saved-addresses-addresses]) + [address-or-ens set-address-or-ens] (rn/use-state "") + [ens-address set-ens-address] (rn/use-state "") + [error set-error] (rn/use-state nil) + error? (some? error) + ens-name? (validation/ens-name? address-or-ens) + address (if ens-name? ens-address address-or-ens) + button-disabled? (or (string/blank? address-or-ens) + (and ens-name? (string/blank? ens-address)) + error?) + validate #(validate-input accounts-addresses + saved-addresses-addresses + %) + clear-input (rn/use-callback + (fn [] + (set-address-or-ens "") + (set-ens-address "") + (set-error nil))) + on-ens-resolve (rn/use-callback + (fn [resolved-address] + (set-error (validate resolved-address)) + (set-ens-address resolved-address))) + on-change-text (rn/use-callback + (fn [new-value] + (let [trimmed-value (string/trim new-value)] + (set-error (validate (string/lower-case trimmed-value))) + (set-address-or-ens trimmed-value) + (set-ens-address "") + (when (validation/ens-name? trimmed-value) + (debounce/debounce-and-dispatch + [:wallet/resolve-ens + {:ens new-value + :on-success on-ens-resolve + :on-error #(set-error :ens-not-registered)}] + 300))))) + paste-into-input (rn/use-callback #(clipboard/get-string + (fn [clipboard-text] + (on-change-text clipboard-text)))) + on-press-continue (rn/use-callback + (fn [] + (rf/dispatch + [:wallet/set-address-to-save + {:address address + :ens address-or-ens + :ens? ens-name?}]) + (rf/dispatch + [:navigate-to-within-stack + [:screen/settings.save-address + :screen/settings.add-address-to-save]])) + [address ens-name? address-or-ens])] (rn/use-unmount #(rf/dispatch [:wallet/clear-address-to-save])) [quo/overlay {:type :shell} [floating-button-page/view @@ -153,8 +176,7 @@ :accessibility-label :add-address-to-save-page-nav}] :footer [quo/button {:customization-color profile-color - :disabled? (or (string/blank? input-value) - error?) + :disabled? button-disabled? :on-press on-press-continue} (i18n/label :t/continue)]} [quo/page-top @@ -164,7 +186,7 @@ :description :text :description-text (i18n/label :t/add-address-to-save-description)}] [address-input - {:input-value input-value + {:input-value address-or-ens :on-change-text on-change-text :paste-into-input paste-into-input :clear-input clear-input}] @@ -172,4 +194,4 @@ [:<> [error-view {:error error}] (when (= error :existing-saved-address) - [existing-saved-address {:address input-value}])])]])) + [existing-saved-address {:address address}])])]])) diff --git a/src/status_im/contexts/settings/wallet/saved_addresses/events_test.cljs b/src/status_im/contexts/settings/wallet/saved_addresses/events_test.cljs index ab42640cd5..6c2e87a405 100644 --- a/src/status_im/contexts/settings/wallet/saved_addresses/events_test.cljs +++ b/src/status_im/contexts/settings/wallet/saved_addresses/events_test.cljs @@ -55,7 +55,7 @@ :address "0x2" :mixedcase-address "0x2" :chain-short-names "eth:arb1:oeth:" - :has-ens? false + :ens? false :network-preferences-names `(:mainnet :arbitrum :optimism) :name "Bob" :created-at 1716826714 @@ -75,7 +75,7 @@ :mixedcase-address "0x2" :chain-short-names "eth:arb1:oeth:" :network-preferences-names `(:mainnet :arbitrum :optimism) - :has-ens? false + :ens? false :name "Bob" :created-at 1716826714 :ens "" @@ -86,7 +86,7 @@ :mixedcase-address "0x1" :chain-short-names "eth:arb1:oeth:" :network-preferences-names `(:mainnet :arbitrum :optimism) - :has-ens? false + :ens? false :name "Amy" :created-at 1716826806 :ens "" diff --git a/src/status_im/contexts/settings/wallet/saved_addresses/save_address/view.cljs b/src/status_im/contexts/settings/wallet/saved_addresses/save_address/view.cljs index 10f432ce5e..bc8fa864db 100644 --- a/src/status_im/contexts/settings/wallet/saved_addresses/save_address/view.cljs +++ b/src/status_im/contexts/settings/wallet/saved_addresses/save_address/view.cljs @@ -35,7 +35,7 @@ (defn view [] - (let [{:keys [address]} (rf/sub [:wallet/saved-address]) + (let [{:keys [address ens ens?]} (rf/sub [:wallet/saved-address]) [network-prefixes address-without-prefix] (utils/split-prefix-and-address address) [address-label set-address-label] (rn/use-state "") [address-color set-address-color] (rn/use-state (rand-nth colors/account-colors)) @@ -46,6 +46,13 @@ selected-networks) [selected-networks]) placeholder (i18n/label :t/address-name) + address-text (rn/use-callback + (fn [] + [quo/address-text + {:full-address? true + :address (str chain-short-names address-without-prefix) + :format :long}]) + [address-without-prefix chain-short-names]) open-network-preferences (rn/use-callback (fn [] (rf/dispatch @@ -68,11 +75,29 @@ :on-error [:wallet/add-saved-address-failed] :name address-label + :ens ens :address address-without-prefix :customization-color address-color :chain-short-names chain-short-names}])) [address-without-prefix chain-short-names address-label - address-color])] + address-color]) + data-item-props (rn/use-memo + #(cond-> {:status :default + :size :default + :subtitle-type :default + :label :none + :blur? true + :icon-right? true + :right-icon :i/advanced + :card? true + :title (i18n/label :t/address) + :subtitle ens + :custom-subtitle address-text + :on-press open-network-preferences + :container-style style/data-item} + ens? + (dissoc :custom-subtitle)) + [ens ens? open-network-preferences address-text])] [quo/overlay {:type :shell} [floating-button-page/view {:footer-container-padding 0 @@ -125,22 +150,4 @@ [quo/divider-line {:blur? true :container-style style/color-picker-bottom-divider}] - [quo/data-item - {:status :default - :size :default - :subtitle-type :default - :label :none - :blur? true - :icon-right? true - :right-icon :i/advanced - :card? true - :title (i18n/label :t/address) - :custom-subtitle (rn/use-callback - (fn [] - [quo/address-text - {:full-address? true - :address (str chain-short-names address-without-prefix) - :format :long}]) - [selected-networks address]) - :on-press open-network-preferences - :container-style style/data-item}]]])) + [quo/data-item data-item-props]]])) diff --git a/src/status_im/contexts/settings/wallet/saved_addresses/sheets/address_options/view.cljs b/src/status_im/contexts/settings/wallet/saved_addresses/sheets/address_options/view.cljs index fbe1a059de..da780b3aad 100644 --- a/src/status_im/contexts/settings/wallet/saved_addresses/sheets/address_options/view.cljs +++ b/src/status_im/contexts/settings/wallet/saved_addresses/sheets/address_options/view.cljs @@ -2,6 +2,7 @@ (:require [clojure.string :as string] [quo.core :as quo] + [quo.foundations.colors :as colors] [react-native.core :as rn] [react-native.platform :as platform] [status-im.common.not-implemented :as not-implemented] @@ -52,10 +53,11 @@ open-remove-confirmation-sheet (rn/use-callback #(rf/dispatch [:show-bottom-sheet - {:theme :dark - :shell? true - :content (fn [] - [remove-address/view opts])}]) + {:theme :dark + :shell? true + :blur-background colors/bottom-sheet-background-blur + :content (fn [] + [remove-address/view opts])}]) [opts]) open-show-address-qr (rn/use-callback #(rf/dispatch [:open-modal diff --git a/src/status_im/contexts/settings/wallet/saved_addresses/view.cljs b/src/status_im/contexts/settings/wallet/saved_addresses/view.cljs index 70ccf94415..a5f3c1991f 100644 --- a/src/status_im/contexts/settings/wallet/saved_addresses/view.cljs +++ b/src/status_im/contexts/settings/wallet/saved_addresses/view.cljs @@ -1,6 +1,7 @@ (ns status-im.contexts.settings.wallet.saved-addresses.view (:require [quo.core :as quo] + [quo.foundations.colors :as colors] [quo.theme :as quo.theme] [react-native.core :as rn] [react-native.safe-area :as safe-area] @@ -20,27 +21,29 @@ :container-style style/empty-container-style}])) (defn- saved-address - [{:keys [name address chain-short-names customization-color has-ens? ens network-preferences-names]}] + [{:keys [name address chain-short-names customization-color ens? ens network-preferences-names]}] (let [full-address (str chain-short-names address) on-press-saved-address (rn/use-callback #(rf/dispatch [:show-bottom-sheet - {:theme :dark - :shell? true - :content (fn [] - [address-options/view - {:address address - :chain-short-names chain-short-names - :full-address full-address - :name name - :network-preferences-names network-preferences-names - :customization-color customization-color}])}]) + {:theme :dark + :shell? true + :blur-background colors/bottom-sheet-background-blur + :content (fn [] + [address-options/view + {:address address + :chain-short-names chain-short-names + :full-address full-address + :name name + :network-preferences-names + network-preferences-names + :customization-color customization-color}])}]) [address chain-short-names full-address name customization-color])] [quo/saved-address {:blur? true :user-props {:name name :address full-address - :ens (when has-ens? ens) + :ens (when ens? ens) :customization-color customization-color :blur? true} :container-style {:margin-horizontal 8} @@ -88,12 +91,13 @@ :icon :i/add :container-style style/title-container}] [rn/section-list - {:key-fn :title - :sticky-section-headers-enabled false - :render-section-header-fn header - :render-section-footer-fn footer - :sections saved-addresses - :render-fn saved-address - :separator [rn/view {:style {:height 4}}] - :content-container-style {:flex-grow 1} - :empty-component [empty-state]}]])) + {:key-fn :title + :shows-vertical-scroll-indicator false + :sticky-section-headers-enabled false + :render-section-header-fn header + :render-section-footer-fn footer + :sections saved-addresses + :render-fn saved-address + :separator [rn/view {:style {:height 4}}] + :content-container-style {:flex-grow 1} + :empty-component [empty-state]}]])) diff --git a/src/status_im/contexts/wallet/common/validation.cljs b/src/status_im/contexts/wallet/common/validation.cljs index bab2ab4af5..f11969db24 100644 --- a/src/status_im/contexts/wallet/common/validation.cljs +++ b/src/status_im/contexts/wallet/common/validation.cljs @@ -1,6 +1,6 @@ (ns status-im.contexts.wallet.common.validation (:require [status-im.constants :as constants])) -(defn ens-name? [s] (re-find constants/regx-ens s)) +(defn ens-name? [s] (boolean (re-find constants/regx-ens s))) (defn eth-address? [s] (re-find constants/regx-multichain-address s)) (defn private-key? [s] (re-find constants/regx-private-key s)) diff --git a/src/status_im/contexts/wallet/data_store.cljs b/src/status_im/contexts/wallet/data_store.cljs index 3efc91937f..5a0fe2d3db 100644 --- a/src/status_im/contexts/wallet/data_store.cljs +++ b/src/status_im/contexts/wallet/data_store.cljs @@ -143,7 +143,7 @@ (-> saved-address (assoc :network-preferences-names (network-utils/network-preference-prefix->network-names (:chain-short-names saved-address))) - (assoc :has-ens? (not (string/blank? (:ens saved-address)))))) + (assoc :ens? (not (string/blank? (:ens saved-address)))))) (defn rpc->saved-address [saved-address] diff --git a/src/status_im/contexts/wallet/events.cljs b/src/status_im/contexts/wallet/events.cljs index 6daf9fe2bf..0696bc7cf1 100644 --- a/src/status_im/contexts/wallet/events.cljs +++ b/src/status_im/contexts/wallet/events.cljs @@ -526,3 +526,13 @@ :on-error #(log/info "failed to fetch crypto on ramps" {:error % :event :wallet/get-crypto-on-ramps})}]]]})) + +(rf/reg-event-fx + :wallet/resolve-ens + (fn [{db :db} [{:keys [ens on-success on-error]}]] + (let [chain-id (network-utils/network->chain-id db constants/mainnet-network-name)] + {:fx [[:json-rpc/call + [{:method "ens_addressOf" + :params [chain-id ens] + :on-success on-success + :on-error on-error}]]]}))) diff --git a/src/status_im/subs/wallet/saved_addresses_test.cljs b/src/status_im/subs/wallet/saved_addresses_test.cljs index 653fa7a122..fa95c31e17 100644 --- a/src/status_im/subs/wallet/saved_addresses_test.cljs +++ b/src/status_im/subs/wallet/saved_addresses_test.cljs @@ -9,7 +9,7 @@ :address "0x1" :mixedcase-address "0x1" :chain-short-names "eth:arb1:oeth:" - :has-ens? false + :ens? false :network-preferences-names #{:arbitrum :optimism :mainnet} @@ -22,7 +22,7 @@ :address "0x2" :mixedcase-address "0x2" :chain-short-names "eth:" - :has-ens? false + :ens? false :network-preferences-names #{:mainnet} :name "Bob" :created-at 1716828825 @@ -33,7 +33,7 @@ :address "0x1" :mixedcase-address "0x1" :chain-short-names "eth:" - :has-ens? false + :ens? false :network-preferences-names #{:mainnet} :name "Alice" :created-at 1716826745 @@ -44,7 +44,7 @@ :address "0x2" :mixedcase-address "0x2" :chain-short-names "eth:arb1:oeth:" - :has-ens? false + :ens? false :network-preferences-names #{:arbitrum :optimism :mainnet} @@ -61,7 +61,7 @@ :address "0x1" :mixedcase-address "0x1" :chain-short-names "eth:" - :has-ens? false + :ens? false :network-preferences-names #{:mainnet} :name "Alice" :created-at 1716826745 @@ -74,7 +74,7 @@ :address "0x2" :mixedcase-address "0x2" :chain-short-names "eth:arb1:oeth:" - :has-ens? false + :ens? false :network-preferences-names #{:arbitrum :optimism :mainnet}