Skip to content

Commit 3c69239

Browse files
authored
[#18736] add address to watch using an ENS (#19043)
* Add capability to register an address based on an ENS * update tests * Check for existing addresses using an ENS
1 parent 7a6714e commit 3c69239

File tree

7 files changed

+179
-122
lines changed

7 files changed

+179
-122
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
(ns status-im.contexts.wallet.accounts.add-account.address-to-watch.events
2+
(:require [clojure.string :as string]
3+
[status-im.constants :as constants]
4+
[taoensso.timbre :as log]
5+
[utils.re-frame :as rf]))
6+
7+
(rf/reg-event-fx
8+
:wallet/ens-not-found
9+
(fn [{:keys [db]} _]
10+
{:db (-> db
11+
(assoc-in [:wallet :ui :add-address-to-watch :activity-state] :invalid-ens)
12+
(assoc-in [:wallet :ui :add-address-to-watch :validated-address] nil))}))
13+
14+
(rf/reg-event-fx
15+
:wallet/store-address-activity
16+
(fn [{:keys [db]} [address {:keys [hasActivity]}]]
17+
(let [registered-addresses (-> db :wallet :accounts keys set)
18+
address-already-registered? (registered-addresses address)]
19+
(if address-already-registered?
20+
{:db (-> db
21+
(assoc-in [:wallet :ui :add-address-to-watch :activity-state]
22+
:address-already-registered)
23+
(assoc-in [:wallet :ui :add-address-to-watch :validated-address] nil))}
24+
(let [state (if hasActivity :has-activity :no-activity)]
25+
{:db (-> db
26+
(assoc-in [:wallet :ui :add-address-to-watch :activity-state] state)
27+
(assoc-in [:wallet :ui :add-address-to-watch :validated-address] address))})))))
28+
29+
(rf/reg-event-fx
30+
:wallet/clear-address-activity
31+
(fn [{:keys [db]}]
32+
{:db (update-in db [:wallet :ui] dissoc :add-address-to-watch)}))
33+
34+
(rf/reg-event-fx
35+
:wallet/get-address-details
36+
(fn [{:keys [db]} [address-or-ens]]
37+
(let [request-params [constants/ethereum-mainnet-chain-id address-or-ens]
38+
ens? (string/includes? address-or-ens ".")]
39+
{:db (-> db
40+
(assoc-in [:wallet :ui :add-address-to-watch :activity-state] :scanning)
41+
(assoc-in [:wallet :ui :add-address-to-watch :validated-address] nil))
42+
:fx [(if ens?
43+
[:json-rpc/call
44+
[{:method "ens_addressOf"
45+
:params request-params
46+
:on-success [:wallet/get-address-details]
47+
:on-error [:wallet/ens-not-found]}]]
48+
[:json-rpc/call
49+
[{:method "wallet_getAddressDetails"
50+
:params request-params
51+
:on-success [:wallet/store-address-activity address-or-ens]
52+
:on-error #(log/info "failed to get address details"
53+
{:error %
54+
:event :wallet/get-address-details})}]])]})))

src/status_im/contexts/wallet/add_address_to_watch/view.cljs

+90-82
Original file line numberDiff line numberDiff line change
@@ -8,22 +8,22 @@
88
[status-im.common.floating-button-page.view :as floating-button-page]
99
[status-im.contexts.wallet.add-address-to-watch.style :as style]
1010
[status-im.contexts.wallet.common.validation :as validation]
11+
[status-im.subs.wallet.add-account.address-to-watch]
12+
[utils.debounce :as debounce]
1113
[utils.i18n :as i18n]
1214
[utils.re-frame :as rf]))
1315

14-
(defn validate-message
15-
[addresses]
16-
(fn [s]
17-
(cond
18-
(or (= s nil) (= s "")) nil
19-
(contains? addresses s) (i18n/label :t/address-already-in-use)
20-
(not (or (validation/eth-address? s)
21-
(validation/ens-name? s))) (i18n/label :t/invalid-address)
22-
:else nil)))
16+
(defn- validate-address
17+
[known-addresses user-input]
18+
(cond
19+
(or (nil? user-input) (= user-input "")) nil
20+
(contains? known-addresses user-input) (i18n/label :t/address-already-in-use)
21+
(not
22+
(or (validation/eth-address? user-input)
23+
(validation/ens-name? user-input))) (i18n/label :t/invalid-address)))
2324

2425
(defn- address-input
25-
[{:keys [input-value validation-msg validate
26-
clear-input]}]
26+
[{:keys [input-value validation-msg validate clear-input]}]
2727
(let [scanned-address (rf/sub [:wallet/scanned-address])
2828
empty-input? (and (string/blank? @input-value)
2929
(string/blank? scanned-address))
@@ -32,10 +32,11 @@
3232
(reset! input-value new-text)
3333
(reagent/flush)
3434
(if (and (not-empty new-text) (nil? (validate new-text)))
35-
(rf/dispatch [:wallet/get-address-details new-text])
36-
(rf/dispatch [:wallet/clear-address-activity-check]))
35+
(debounce/debounce-and-dispatch [:wallet/get-address-details new-text]
36+
500)
37+
(rf/dispatch [:wallet/clear-address-activity]))
3738
(when (and scanned-address (not= scanned-address new-text))
38-
(rf/dispatch [:wallet/clear-address-activity-check])
39+
(rf/dispatch [:wallet/clear-address-activity])
3940
(rf/dispatch [:wallet/clean-scanned-address])))
4041
paste-on-input #(clipboard/get-string
4142
(fn [clipboard-text]
@@ -44,8 +45,7 @@
4445
(when-not (string/blank? scanned-address)
4546
(on-change-text scanned-address)))
4647
[scanned-address])
47-
[rn/view
48-
{:style style/input-container}
48+
[rn/view {:style style/input-container}
4949
[quo/input
5050
{:accessibility-label :add-address-to-watch
5151
:placeholder (i18n/label :t/address-placeholder)
@@ -72,84 +72,92 @@
7272
:i/scan]]))
7373

7474
(defn activity-indicator
75-
[]
76-
(let [activity-state (rf/sub [:wallet/watch-address-activity-state])
77-
{:keys [accessibility-label icon type message]}
78-
(case activity-state
79-
:has-activity {:accessibility-label :account-has-activity
80-
:icon :i/done
81-
:type :success
82-
:message :t/this-address-has-activity}
83-
:no-activity {:accessibility-label :account-has-no-activity
84-
:icon :i/info
85-
:type :warning
86-
:message :t/this-address-has-no-activity}
87-
{:accessibility-label :searching-for-activity
88-
:icon :i/pending-state
89-
:type :default
90-
:message :t/searching-for-activity})]
75+
[activity-state]
76+
(let [{:keys [message]
77+
:as props} (case activity-state
78+
:has-activity {:accessibility-label :account-has-activity
79+
:icon :i/done
80+
:type :success
81+
:message :t/this-address-has-activity}
82+
:no-activity {:accessibility-label :account-has-no-activity
83+
:icon :i/info
84+
:type :warning
85+
:message :t/this-address-has-no-activity}
86+
:invalid-ens {:accessibility-label :error-message
87+
:icon :i/info
88+
:type :error
89+
:message :t/invalid-address}
90+
:address-already-registered {:accessibility-label :error-message
91+
:icon :i/info
92+
:type :error
93+
:message :t/address-already-in-use}
94+
{:accessibility-label :searching-for-activity
95+
:icon :i/pending-state
96+
:type :default
97+
:message :t/searching-for-activity})]
9198
(when activity-state
9299
[quo/info-message
93-
{:accessibility-label accessibility-label
94-
:size :default
95-
:icon icon
96-
:type type
97-
:style style/info-message}
100+
(assoc props
101+
:style style/info-message
102+
:size :default)
98103
(i18n/label message)])))
99104

100105
(defn view
101106
[]
102107
(let [addresses (rf/sub [:wallet/addresses])
103108
input-value (reagent/atom nil)
104-
validate (validate-message (set addresses))
105-
validation-msg (reagent/atom (validate
106-
@input-value))
109+
validate #(validate-address (set addresses) %)
110+
validation-msg (reagent/atom nil)
107111
clear-input (fn []
108112
(reset! input-value nil)
109113
(reset! validation-msg nil)
110-
(rf/dispatch [:wallet/clear-address-activity-check])
114+
(rf/dispatch [:wallet/clear-address-activity])
111115
(rf/dispatch [:wallet/clean-scanned-address]))
112116
customization-color (rf/sub [:profile/customization-color])]
113117
(rf/dispatch [:wallet/clean-scanned-address])
114-
(rf/dispatch [:wallet/clear-address-activity-check])
118+
(rf/dispatch [:wallet/clear-address-activity])
115119
(fn []
116-
[rn/view
117-
{:style {:flex 1}}
118-
[floating-button-page/view
119-
{:header [quo/page-nav
120-
{:type :no-title
121-
:icon-name :i/close
122-
:on-press (fn []
123-
(rf/dispatch [:wallet/clean-scanned-address])
124-
(rf/dispatch [:wallet/clear-address-activity-check])
125-
(rf/dispatch [:navigate-back]))}]
126-
:footer [quo/button
127-
{:customization-color customization-color
128-
:disabled? (or (string/blank? @input-value)
129-
(some? (validate @input-value)))
130-
:on-press (fn []
131-
(rf/dispatch [:navigate-to
132-
:confirm-address-to-watch
133-
{:address @input-value}])
134-
(clear-input))
135-
:container-style {:z-index 2}}
136-
(i18n/label :t/continue)]}
137-
[quo/page-top
138-
{:container-style style/header-container
139-
:title (i18n/label :t/add-address)
140-
:description :text
141-
:description-text (i18n/label :t/enter-eth)}]
142-
[:f> address-input
143-
{:input-value input-value
144-
:validate validate
145-
:validation-msg validation-msg
146-
:clear-input clear-input}]
147-
(when @validation-msg
148-
[quo/info-message
149-
{:accessibility-label :error-message
150-
:size :default
151-
:icon :i/info
152-
:type :error
153-
:style style/info-message}
154-
@validation-msg])
155-
[activity-indicator]]])))
120+
(let [activity-state (rf/sub [:wallet/watch-address-activity-state])
121+
validated-address (rf/sub [:wallet/watch-address-validated-address])]
122+
[rn/view {:style {:flex 1}}
123+
[floating-button-page/view
124+
{:header [quo/page-nav
125+
{:type :no-title
126+
:icon-name :i/close
127+
:on-press (fn []
128+
(rf/dispatch [:wallet/clean-scanned-address])
129+
(rf/dispatch [:wallet/clear-address-activity])
130+
(rf/dispatch [:navigate-back]))}]
131+
:footer [quo/button
132+
{:customization-color customization-color
133+
:disabled? (or (string/blank? @input-value)
134+
(some? (validate @input-value))
135+
(= activity-state :invalid-ens)
136+
(= activity-state :scanning)
137+
(not validated-address))
138+
:on-press (fn []
139+
(rf/dispatch [:navigate-to
140+
:confirm-address-to-watch
141+
{:address validated-address}])
142+
(clear-input))
143+
:container-style {:z-index 2}}
144+
(i18n/label :t/continue)]}
145+
[quo/page-top
146+
{:container-style style/header-container
147+
:title (i18n/label :t/add-address)
148+
:description :text
149+
:description-text (i18n/label :t/enter-eth)}]
150+
[:f> address-input
151+
{:input-value input-value
152+
:validate validate
153+
:validation-msg validation-msg
154+
:clear-input clear-input}]
155+
(if @validation-msg
156+
[quo/info-message
157+
{:accessibility-label :error-message
158+
:size :default
159+
:icon :i/info
160+
:type :error
161+
:style style/info-message}
162+
@validation-msg]
163+
[activity-indicator activity-state])]]))))

src/status_im/contexts/wallet/events.cljs

+1-22
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@
44
[react-native.background-timer :as background-timer]
55
[react-native.platform :as platform]
66
[status-im.constants :as constants]
7+
[status-im.contexts.wallet.accounts.add-account.address-to-watch.events]
78
[status-im.contexts.wallet.common.utils :as utils]
89
[status-im.contexts.wallet.data-store :as data-store]
910
[status-im.contexts.wallet.events.collectibles]
1011
[status-im.contexts.wallet.item-types :as item-types]
1112
[taoensso.timbre :as log]
1213
[utils.collection]
13-
[utils.ethereum.chain :as chain]
1414
[utils.ethereum.eip.eip55 :as eip55]
1515
[utils.i18n :as i18n]
1616
[utils.number]
@@ -360,27 +360,6 @@
360360
(fn [{:keys [db]}]
361361
{:db (assoc db :wallet/valid-ens-or-address? false)}))
362362

363-
(rf/reg-event-fx :wallet/get-address-details-success
364-
(fn [{:keys [db]} [{:keys [hasActivity]}]]
365-
{:db (assoc-in db
366-
[:wallet :ui :watch-address-activity-state]
367-
(if hasActivity :has-activity :no-activity))}))
368-
369-
(rf/reg-event-fx :wallet/clear-address-activity-check
370-
(fn [{:keys [db]}]
371-
{:db (update-in db [:wallet :ui] dissoc :watch-address-activity-state)}))
372-
373-
(rf/reg-event-fx :wallet/get-address-details
374-
(fn [{:keys [db]} [address]]
375-
{:db (assoc-in db [:wallet :ui :watch-address-activity-state] :scanning)
376-
:fx [[:json-rpc/call
377-
[{:method "wallet_getAddressDetails"
378-
:params [(chain/chain-id db) address]
379-
:on-success [:wallet/get-address-details-success]
380-
:on-error #(log/info "failed to get address details"
381-
{:error %
382-
:event :wallet/get-address-details})}]]]}))
383-
384363
(rf/reg-event-fx
385364
:wallet/navigate-to-chain-explorer-from-bottom-sheet
386365
(fn [_ [explorer-link address]]

src/status_im/contexts/wallet/send/select_address/view.cljs

+9-10
Original file line numberDiff line numberDiff line change
@@ -115,16 +115,15 @@
115115

116116
(defn- local-suggestions-list
117117
[]
118-
(fn []
119-
(let [local-suggestion (rf/sub [:wallet/local-suggestions])]
120-
[rn/view {:style {:flex 1}}
121-
[rn/flat-list
122-
{:data local-suggestion
123-
:content-container-style {:flex-grow 1}
124-
:key-fn :id
125-
:on-scroll-to-index-failed identity
126-
:keyboard-should-persist-taps :handled
127-
:render-fn suggestion-component}]])))
118+
(let [local-suggestion (rf/sub [:wallet/local-suggestions])]
119+
[rn/view {:style {:flex 1}}
120+
[rn/flat-list
121+
{:data local-suggestion
122+
:content-container-style {:flex-grow 1}
123+
:key-fn :id
124+
:on-scroll-to-index-failed identity
125+
:keyboard-should-persist-taps :handled
126+
:render-fn suggestion-component}]]))
128127

129128
(defn- f-view
130129
[]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
(ns status-im.subs.wallet.add-account.address-to-watch
2+
(:require [re-frame.core :as rf]))
3+
4+
(rf/reg-sub
5+
:wallet/add-address-to-watch
6+
:<- [:wallet/ui]
7+
:-> :add-address-to-watch)
8+
9+
(rf/reg-sub
10+
:wallet/watch-address-activity-state
11+
:<- [:wallet/add-address-to-watch]
12+
:-> :activity-state)
13+
14+
(rf/reg-sub
15+
:wallet/watch-address-validated-address
16+
:<- [:wallet/add-address-to-watch]
17+
:-> :validated-address)

src/status_im/subs/wallet/wallet.cljs

+1-5
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
(:require [clojure.string :as string]
33
[re-frame.core :as rf]
44
[status-im.contexts.wallet.common.utils :as utils]
5+
[status-im.subs.wallet.add-account.address-to-watch]
56
[utils.number]))
67

78
(defn- filter-networks
@@ -93,11 +94,6 @@
9394
:<- [:wallet/wallet-send]
9495
:-> :bridge-to-chain-id)
9596

96-
(rf/reg-sub
97-
:wallet/watch-address-activity-state
98-
:<- [:wallet/ui]
99-
:-> :watch-address-activity-state)
100-
10197
(rf/reg-sub
10298
:wallet/keypairs
10399
:<- [:wallet]

src/status_im/subs/wallet/wallet_test.cljs

+7-3
Original file line numberDiff line numberDiff line change
@@ -296,12 +296,16 @@
296296
(is (nil? (rf/sub [sub-name]))))
297297

298298
(testing "watch address activity state with no-activity value"
299-
(swap! rf-db/app-db #(assoc-in % [:wallet :ui :watch-address-activity-state] :no-activity))
299+
(swap! rf-db/app-db #(assoc-in % [:wallet :ui :add-address-to-watch :activity-state] :no-activity))
300300
(is (match? :no-activity (rf/sub [sub-name]))))
301301

302302
(testing "watch address activity state with has-activity value"
303-
(swap! rf-db/app-db #(assoc-in % [:wallet :ui :watch-address-activity-state] :has-activity))
304-
(is (match? :has-activity (rf/sub [sub-name])))))
303+
(swap! rf-db/app-db #(assoc-in % [:wallet :ui :add-address-to-watch :activity-state] :has-activity))
304+
(is (match? :has-activity (rf/sub [sub-name]))))
305+
306+
(testing "watch address activity state with invalid-ens value"
307+
(swap! rf-db/app-db #(assoc-in % [:wallet :ui :add-address-to-watch :activity-state] :invalid-ens))
308+
(is (match? :invalid-ens (rf/sub [sub-name])))))
305309

306310
(h/deftest-sub :wallet/accounts-without-current-viewing-account
307311
[sub-name]

0 commit comments

Comments
 (0)