feat(wallet): sync saved addresses (#20546)

This commit adds syncing saved addresses across paired devices whenever a new saved address is added or an existing one is edited or removed.

Signed-off-by: Mohamed Javid <19339952+smohamedjavid@users.noreply.github.com>
This commit is contained in:
Mohamed Javid 2024-07-02 15:33:54 +05:30 committed by GitHub
parent ef9cc55501
commit 0581fc2f9d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 152 additions and 51 deletions

View File

@ -21,6 +21,7 @@
[status-im.contexts.chat.messenger.messages.pin.events :as messages.pin] [status-im.contexts.chat.messenger.messages.pin.events :as messages.pin]
[status-im.contexts.communities.events :as communities] [status-im.contexts.communities.events :as communities]
[status-im.contexts.shell.activity-center.events :as activity-center] [status-im.contexts.shell.activity-center.events :as activity-center]
[status-im.contexts.wallet.data-store :as wallet.data-store]
[taoensso.timbre :as log] [taoensso.timbre :as log]
[utils.re-frame :as rf])) [utils.re-frame :as rf]))
@ -56,6 +57,7 @@
^js accounts (.-accounts response-js) ^js accounts (.-accounts response-js)
^js ens-username-details-js (.-ensUsernameDetails response-js) ^js ens-username-details-js (.-ensUsernameDetails response-js)
^js customization-color-js (.-customizationColor response-js) ^js customization-color-js (.-customizationColor response-js)
^js saved-addresses-js (.-savedAddresses response-js)
sync-handler (when-not process-async process-response)] sync-handler (when-not process-async process-response)]
(cond (cond
@ -199,6 +201,13 @@
(models.visibility-status-updates/sync-visibility-status-update (models.visibility-status-updates/sync-visibility-status-update
current-visibility-status-clj))) current-visibility-status-clj)))
(seq saved-addresses-js)
(let [saved-addresses (-> saved-addresses-js types/js->clj wallet.data-store/rpc->saved-addresses)]
(js-delete response-js "savedAddresses")
(rf/merge cofx
{:fx [[:dispatch [:wallet/reconcile-saved-addresses saved-addresses]]]}
(process-next response-js sync-handler)))
(seq ens-username-details-js) (seq ens-username-details-js)
(let [ens-username-details-clj (types/js->clj ens-username-details-js)] (let [ens-username-details-clj (types/js->clj ens-username-details-js)]
(js-delete response-js "ensUsernameDetails") (js-delete response-js "ensUsernameDetails")

View File

@ -23,15 +23,29 @@
(rf/reg-event-fx :wallet/save-address save-address) (rf/reg-event-fx :wallet/save-address save-address)
(defn- update-saved-addresses
[saved-addresses-db new-saved-addresses]
(reduce
(fn [acc {:keys [address removed? test?] :as saved-address}]
(let [db-key (if test? :test :prod)]
(if removed?
(update acc db-key dissoc address)
(assoc-in acc [db-key address] saved-address))))
(or saved-addresses-db
{:test {}
:prod {}})
new-saved-addresses))
(defn reconcile-saved-addresses
[{:keys [db]} [saved-addresses]]
{:db (update-in db [:wallet :saved-addresses] update-saved-addresses saved-addresses)})
(rf/reg-event-fx :wallet/reconcile-saved-addresses reconcile-saved-addresses)
(defn get-saved-addresses-success (defn get-saved-addresses-success
[{:keys [db]} [raw-saved-addresses]] [_ [raw-saved-addresses]]
(let [saved-addresses (reduce (let [saved-addresses (data-store/rpc->saved-addresses raw-saved-addresses)]
(fn [result {:keys [address test?] :as saved-address}] {:fx [[:dispatch [:wallet/reconcile-saved-addresses saved-addresses]]]}))
(assoc-in result [(if test? :test :prod) address] saved-address))
{:test {}
:prod {}}
(data-store/rpc->saved-addresses raw-saved-addresses))]
{:db (assoc-in db [:wallet :saved-addresses] saved-addresses)}))
(rf/reg-event-fx :wallet/get-saved-addresses-success get-saved-addresses-success) (rf/reg-event-fx :wallet/get-saved-addresses-success get-saved-addresses-success)
@ -52,15 +66,17 @@
(rf/reg-event-fx :wallet/get-saved-addresses get-saved-addresses) (rf/reg-event-fx :wallet/get-saved-addresses get-saved-addresses)
(defn delete-saved-address-success (defn delete-saved-address-success
[_ [toast-message]] [{:keys [db]} [{:keys [address test-networks-enabled? toast-message]}]]
{:fx [[:dispatch [:wallet/get-saved-addresses]] (let [db-key (if test-networks-enabled? :test :prod)
[:dispatch [:hide-bottom-sheet]] saved-address (get-in db [:wallet :saved-addresses db-key address])]
[:dispatch-later {:fx [[:dispatch [:wallet/reconcile-saved-addresses [(assoc saved-address :removed? true)]]]
{:ms 100 [:dispatch [:hide-bottom-sheet]]
:dispatch [:toasts/upsert [:dispatch-later
{:type :positive {:ms 100
:theme :dark :dispatch [:toasts/upsert
:text toast-message}]}]]}) {:type :positive
:theme :dark
:text toast-message}]}]]}))
(rf/reg-event-fx :wallet/delete-saved-address-success delete-saved-address-success) (rf/reg-event-fx :wallet/delete-saved-address-success delete-saved-address-success)
@ -82,7 +98,10 @@
{:fx [[:json-rpc/call {:fx [[:json-rpc/call
[{:method "wakuext_deleteSavedAddress" [{:method "wakuext_deleteSavedAddress"
:params [address test-networks-enabled?] :params [address test-networks-enabled?]
:on-success [:wallet/delete-saved-address-success toast-message] :on-success [:wallet/delete-saved-address-success
{:address address
:test-networks-enabled? test-networks-enabled?
:toast-message toast-message}]
:on-error [:wallet/delete-saved-address-failed]}]]]})) :on-error [:wallet/delete-saved-address-failed]}]]]}))
(rf/reg-event-fx :wallet/delete-saved-address delete-saved-address) (rf/reg-event-fx :wallet/delete-saved-address delete-saved-address)

View File

@ -2,7 +2,8 @@
(:require (:require
[cljs.test :refer-macros [deftest is testing]] [cljs.test :refer-macros [deftest is testing]]
matcher-combinators.test matcher-combinators.test
[status-im.contexts.settings.wallet.saved-addresses.events :as events])) [status-im.contexts.settings.wallet.saved-addresses.events :as events]
[status-im.contexts.wallet.data-store :as data-store]))
(deftest get-saved-addresses-test (deftest get-saved-addresses-test
(testing "get saved addresses - dispatches RPC call" (testing "get saved addresses - dispatches RPC call"
@ -15,7 +16,7 @@
:on-error [:wallet/saved-addresses-rpc-error :get-saved-addresses]}]]]] :on-error [:wallet/saved-addresses-rpc-error :get-saved-addresses]}]]]]
(is (match? expected-fx result-fx))))) (is (match? expected-fx result-fx)))))
(def saved-address-1 (def saved-address-rpc-1
{:isTest false {:isTest false
:address "0x1" :address "0x1"
:mixedcaseAddress "0x1" :mixedcaseAddress "0x1"
@ -26,21 +27,45 @@
:colorId "purple" :colorId "purple"
:removed false}) :removed false})
(def saved-address-1
{:test? true
:address "0x1"
:mixedcase-address "0x1"
:chain-short-names "eth:oeth:"
:network-preferences-names `(:mainnet :optimism)
:name "Bob"
:created-at 1716826714
:ens ""
:ens? false
:customization-color :blue
:removed? false})
(def saved-address-2 (def saved-address-2
{:isTest true {:test? false
:address "0x2" :address "0x2"
:mixedcaseAddress "0x2" :mixedcase-address "0x2"
:chainShortNames "eth:arb1:oeth:" :chain-short-names "eth:arb1:oeth:"
:name "Bob" :network-preferences-names `(:mainnet :arbitrum :optimism)
:createdAt 1716826714 :name "Alicia Keys"
:ens "" :created-at 1716826806
:colorId "blue" :ens "alicia.eth"
:removed false}) :ens? true
:customization-color :purple
:removed? false})
(deftest get-saved-addresses-success-test (deftest get-saved-addresses-success-test
(let [cofx {:db {}}
raw-saved-addresses [saved-address-rpc-1]
effects (events/get-saved-addresses-success cofx [raw-saved-addresses])
saved-addresses (data-store/rpc->saved-addresses raw-saved-addresses)
result-fx (:fx effects)
expected-fx [[:dispatch [:wallet/reconcile-saved-addresses saved-addresses]]]]
(is (match? expected-fx result-fx))))
(deftest reconcile-saved-addresses-test
(testing "no saved addresses" (testing "no saved addresses"
(let [cofx {:db {}} (let [cofx {:db {}}
effects (events/get-saved-addresses-success cofx nil) effects (events/reconcile-saved-addresses cofx nil)
result-db (:db effects) result-db (:db effects)
expected-db {:wallet {:saved-addresses {:test {} expected-db {:wallet {:saved-addresses {:test {}
:prod {}}}}] :prod {}}}}]
@ -48,15 +73,15 @@
(testing "one test saved address" (testing "one test saved address"
(let [cofx {:db {}} (let [cofx {:db {}}
effects (events/get-saved-addresses-success cofx [[saved-address-2]]) effects (events/reconcile-saved-addresses cofx [[saved-address-1]])
result-db (:db effects) result-db (:db effects)
expected-db {:wallet {:saved-addresses expected-db {:wallet {:saved-addresses
{:test {"0x2" {:test? true {:test {"0x1" {:test? true
:address "0x2" :address "0x1"
:mixedcase-address "0x2" :mixedcase-address "0x1"
:chain-short-names "eth:arb1:oeth:" :chain-short-names "eth:oeth:"
:ens? false :ens? false
:network-preferences-names `(:mainnet :arbitrum :optimism) :network-preferences-names `(:mainnet :optimism)
:name "Bob" :name "Bob"
:created-at 1716826714 :created-at 1716826714
:ens "" :ens ""
@ -67,29 +92,73 @@
(testing "two saved addresses (test and prod)" (testing "two saved addresses (test and prod)"
(let [cofx {:db {}} (let [cofx {:db {}}
effects (events/get-saved-addresses-success cofx [[saved-address-1 saved-address-2]]) effects (events/reconcile-saved-addresses cofx [[saved-address-1 saved-address-2]])
result-db (:db effects) result-db (:db effects)
expected-db {:wallet {:saved-addresses expected-db {:wallet {:saved-addresses
{:test {"0x2" {:test? true {:test {"0x1" {:test? true
:address "0x2" :address "0x1"
:mixedcase-address "0x2" :mixedcase-address "0x1"
:chain-short-names "eth:arb1:oeth:" :chain-short-names "eth:oeth:"
:network-preferences-names `(:mainnet :arbitrum :optimism)
:ens? false :ens? false
:network-preferences-names `(:mainnet :optimism)
:name "Bob" :name "Bob"
:created-at 1716826714 :created-at 1716826714
:ens "" :ens ""
:customization-color :blue :customization-color :blue
:removed? false}} :removed? false}}
:prod {"0x1" {:test? false :prod {"0x2" {:test? false
:address "0x1" :address "0x2"
:mixedcase-address "0x1" :mixedcase-address "0x2"
:chain-short-names "eth:arb1:oeth:" :chain-short-names "eth:arb1:oeth:"
:network-preferences-names `(:mainnet :arbitrum :optimism) :network-preferences-names `(:mainnet :arbitrum :optimism)
:ens? false :ens? true
:name "Amy" :name "Alicia Keys"
:created-at 1716826806 :created-at 1716826806
:ens "" :ens "alicia.eth"
:customization-color :purple
:removed? false}}}}}]
(is (match? expected-db result-db))))
(testing "remove a test saved addresses"
(let [cofx {:db {:wallet {:saved-addresses
{:test {"0x1" {:test? true
:address "0x1"
:mixedcase-address "0x1"
:chain-short-names "eth:oeth:"
:ens? false
:network-preferences-names `(:mainnet :optimism)
:name "Bob"
:created-at 1716826714
:ens ""
:customization-color :blue
:removed? false}}
:prod {"0x2" {:test? false
:address "0x2"
:mixedcase-address "0x2"
:chain-short-names "eth:arb1:oeth:"
:network-preferences-names `(:mainnet :arbitrum
:optimism)
:ens? true
:name "Alicia Keys"
:created-at 1716826806
:ens "alicia.eth"
:customization-color :purple
:removed? false}}}}}}
effects (events/reconcile-saved-addresses cofx
[[(assoc saved-address-1 :removed? true)
saved-address-2]])
result-db (:db effects)
expected-db {:wallet {:saved-addresses
{:test {}
:prod {"0x2" {:test? false
:address "0x2"
:mixedcase-address "0x2"
:chain-short-names "eth:arb1:oeth:"
:network-preferences-names `(:mainnet :arbitrum :optimism)
:ens? true
:name "Alicia Keys"
:created-at 1716826806
:ens "alicia.eth"
:customization-color :purple :customization-color :purple
:removed? false}}}}}] :removed? false}}}}}]
(is (match? expected-db result-db))))) (is (match? expected-db result-db)))))
@ -141,7 +210,10 @@
expected-fx [[:json-rpc/call expected-fx [[:json-rpc/call
[{:method "wakuext_deleteSavedAddress" [{:method "wakuext_deleteSavedAddress"
:params [address test-networks-enabled?] :params [address test-networks-enabled?]
:on-success [:wallet/delete-saved-address-success toast-message] :on-success [:wallet/delete-saved-address-success
{:address address
:test-networks-enabled? test-networks-enabled?
:toast-message toast-message}]
:on-error [:wallet/delete-saved-address-failed]}]]]] :on-error [:wallet/delete-saved-address-failed]}]]]]
(is (match? expected-fx result-fx))))) (is (match? expected-fx result-fx)))))

View File

@ -109,7 +109,7 @@
:on-press open-show-address-qr :on-press open-show-address-qr
:accessibility-label :show-address-qr-code} :accessibility-label :show-address-qr-code}
{:icon :i/edit {:icon :i/edit
:label (i18n/label :t/edit-account) :label (i18n/label :t/edit-details)
:blur? true :blur? true
:on-press open-edit-saved-address :on-press open-edit-saved-address
:accessibility-label :edit-saved-address} :accessibility-label :edit-saved-address}

View File

@ -154,7 +154,7 @@
:colorId :customization-color :colorId :customization-color
:mixedcaseAddress :mixedcase-address :mixedcaseAddress :mixedcase-address
:removed :removed?}) :removed :removed?})
(update :customization-color keyword) (update :customization-color (comp keyword string/lower-case))
add-keys-to-saved-address)) add-keys-to-saved-address))
(defn rpc->saved-addresses (defn rpc->saved-addresses

View File

@ -2507,6 +2507,7 @@
"disconnect-dapp-success": "{{dapp}} disconnected from {{account}}", "disconnect-dapp-success": "{{dapp}} disconnected from {{account}}",
"disconnect-dapp-fail": "Failed to disconnect {{dapp}} from {{account}}", "disconnect-dapp-fail": "Failed to disconnect {{dapp}} from {{account}}",
"edit-account": "Edit account", "edit-account": "Edit account",
"edit-details": "Edit details",
"share-account": "Share account", "share-account": "Share account",
"remove-account": "Remove account", "remove-account": "Remove account",
"select-another-account": "Select another account", "select-another-account": "Select another account",