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:
parent
ef9cc55501
commit
0581fc2f9d
|
@ -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")
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)))))
|
||||||
|
|
||||||
|
|
|
@ -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}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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",
|
||||||
|
|
Loading…
Reference in New Issue